XSLT用于包装特定条件下的紧随的后续同级元素

huangapple go评论52阅读模式
英文:

XSLT for wrapping immediate following-siblings of certain condition

问题

以下是您提供的XML的翻译,包括XSLT代码部分:

<root>
  <i type="r"/>
  <i type="s"/>
  <i type="r"/>
  <i type="r"/>
  <i type="s"/>
  <i type="r"/>
  <i type="s"/>
</root>

我的目标是将所有 <i type="s"> 节点与所有紧随其后的类型为 "r" 的节点(1..n)一起包装起来。

不包装的情况:

  • 没有前置 "s" 节点的 "r" 节点
  • 没有紧随后续 "r" 节点的 "s" 节点

预期输出:

<i type="r"/>
<wrap>
  <i type="s"/>
  <i type="r"/>
  <i type="r"/>
</wrap&gt;
&lt;wrap&gt;
  &lt;i type=&quot;s&quot;/&gt;
  &lt;i type=&quot;r&quot;/&gt;
</wrap&gt;
&lt;i type=&quot;s&quot;/&gt;

我一直在尝试使用以下XSLT代码片段解决问题:

&lt;xsl:for-each select=&quot;./i&quot;&gt;
  &lt;xsl:choose&gt;
    &lt;xsl:when test=&quot;current()[./@type=&#39;r&#39; and count(preceding-sibling::i[@type=&#39;s&#39;]) = 0]&quot;&gt;
      &lt;!-- 处理不包装 --&gt;
      &lt;xsl:apply-templates select=&quot;current()&quot; mode=&quot;fill&quot;/&gt;
    &lt;/xsl:when&gt;
    &lt;xsl:when test=&quot;current()[./@type=&#39;s&#39; and following-sibling::i[@type=&#39;s&#39;]]&quot;&gt;
      &lt;!-- 处理不包装 --&gt;
      &lt;xsl:apply-templates select=&quot;current()&quot; mode=&quot;fill&quot;/&gt;
    &lt;/xsl:when&gt;
    &lt;xsl:when test=&quot;current()[./@type=&#39;r&#39; and count(preceding-sibling::i[@type=&#39;s&#39;]) &gt; 0]&quot;&gt;
      &lt;!-- 什么都不做 --&gt;
    &lt;/xsl:when&gt;
    &lt;xsl:when test=&quot;current()[./@type=&#39;s&#39; and following-sibling::i[1][@type=&#39;r&#39;]]&quot;&gt;
      &lt;wrap&gt;
        &lt;xsl:apply-templates select=&quot;current() | //i[@type=&#39;r&#39; and preceding-sibling::i[@type=&#39;s&#39;]&quot; mode=&quot;fill&quot;/&gt;
      &lt;/wrap&gt;
    &lt;/xsl:when&gt;
  &lt;/xsl:choose&gt;
&lt;/xsl:for-each&gt;

需要注意的是,后续的模板会处理所有的 &lt;I&gt; 节点。这些模板由于与问题本身无关而被省略了。

英文:

I have the following source XML

&lt;root&gt;
  &lt;i type=&quot;r&quot;/&gt;
  &lt;i type=&quot;s&quot;/&gt;
  &lt;i type=&quot;r&quot;/&gt;
  &lt;i type=&quot;r&quot;/&gt;
  &lt;i type=&quot;s&quot;/&gt;
  &lt;i type=&quot;r&quot;/&gt;
  &lt;i type=&quot;s&quot;/&gt;
&lt;/root&gt;

My goal is to wrap together all <i type="s"> occurrences with all immediate following-siblings (1..n) of type="r".

No wrapping for:

  • type="r" nodes w/o preceding type="s" node
  • type="s" nodes w/o immediate following type="r" node

Expected output:

&lt;i type=&quot;r&quot;/&gt;
&lt;wrap&gt;
  &lt;i type=&quot;s&quot;/&gt;
  &lt;i type=&quot;r&quot;/&gt;
  &lt;i type=&quot;r&quot;/&gt;
&lt;/wrap&gt;
&lt;wrap&gt;
  &lt;i type=&quot;s&quot;/&gt;
  &lt;i type=&quot;r&quot;/&gt;
&lt;/wrap&gt;
&lt;i type=&quot;s&quot;/&gt;

I have been trying to resolve the problem with the following XSLT snippet:

&lt;xsl:for-each select=&quot;./i&quot;&gt;
  &lt;xsl:choose&gt;
    &lt;xsl:when test=&quot;current()[./@type=&#39;r&#39; and count(preceding-sibling::i[@type=&#39;s&#39;]) = 0]&quot;&gt;
      &lt;!-- Processing w/o wrap --&gt;
      &lt;xsl:apply-templates select=&quot;current()&quot; mode=&quot;fill&quot;/&gt;
    &lt;/xsl:when&gt;
    &lt;xsl:when test=&quot;current()[./@type=&#39;s&#39; and following-sibling::i[@type=&#39;s&#39;]]&quot;&gt;
      &lt;!-- Processing w/o wrap --&gt;
      &lt;xsl:apply-templates select=&quot;current()&quot; mode=&quot;fill&quot;/&gt;
    &lt;/xsl:when&gt;
    &lt;xsl:when test=&quot;current()[./@type=&#39;r&#39; and count(preceding-sibling::i[@type=&#39;s&#39;]) &gt; 0]&quot;&gt;
      &lt;!-- Do nothing --&gt;
    &lt;/xsl:when&gt;
    &lt;xsl:when test=&quot;current()[./@type=&#39;s&#39; and following-sibling::i[1][@type=&#39;r&#39;]]&quot;&gt;
      &lt;wrap&gt;
        &lt;xsl:apply-templates select=&quot;current() | //i[@type=&#39;r&#39; and preceding-sibling::i[@type=&#39;s&#39;]&quot; mode=&quot;fill&quot;/&gt;
      &lt;/wrap&gt;
    &lt;/xsl:when&gt;
  &lt;/xsl:choose&gt;
&lt;/xsl:for-each&gt;

I'm constantly failing in defining the right context inside <wrap> </wrap>.

Need to note that subsequent templates are processing all <I> nodes. These templates have been omitted due to being irrelevant to the problem itself.

答案1

得分: 0

考虑以下示例:

XML

<root>
   <i type="r">1</i>
   <i type="s">2</i>
   <i type="r">3</i>
   <i type="r">4</i>
   <i type="s">5</i>
   <i type="r">6</i>
   <i type="s">7</i>
</root>

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="r" match="i[@type='r']" use="generate-id(preceding-sibling::i[@type='s'][1])" />

<xsl:template match="/root">
   <xsl:copy>
       <xsl:copy-of select="key('r', '')"/>
       <xsl:for-each select="i[@type='s']">
           <xsl:variable name="r" select="key('r', generate-id())" />
           <xsl:choose>
               <xsl:when test="$r">
                   <wrap>
                       <xsl:copy-of select=". | $r"/>
                   </wrap>
               </xsl:when>
               <xsl:otherwise>
                   <xsl:copy-of select="."/>
               </xsl:otherwise>
           </xsl:choose>
       </xsl:for-each>
   </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Result

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <i type="r">1</i>
   <wrap>
      <i type="s">2</i>
      <i type="r">3</i>
      <i type="r">4</i>
   </wrap>
   <wrap>
      <i type="s">5</i>
      <i type="r">6</i>
   </wrap>
   <i type="s">7</i>
</root>
英文:

Consider the following example:

XML

&lt;root&gt;
  &lt;i type=&quot;r&quot;&gt;1&lt;/i&gt;
  &lt;i type=&quot;s&quot;&gt;2&lt;/i&gt;
  &lt;i type=&quot;r&quot;&gt;3&lt;/i&gt;
  &lt;i type=&quot;r&quot;&gt;4&lt;/i&gt;
  &lt;i type=&quot;s&quot;&gt;5&lt;/i&gt;
  &lt;i type=&quot;r&quot;&gt;6&lt;/i&gt;
  &lt;i type=&quot;s&quot;&gt;7&lt;/i&gt;
&lt;/root&gt;

XSLT 1.0

&lt;xsl:stylesheet version=&quot;1.0&quot; 
xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;
&lt;xsl:output method=&quot;xml&quot; version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; indent=&quot;yes&quot;/&gt;
&lt;xsl:strip-space elements=&quot;*&quot;/&gt;

&lt;xsl:key name=&quot;r&quot; match=&quot;i[@type=&#39;r&#39;]&quot; use=&quot;generate-id(preceding-sibling::i[@type=&#39;s&#39;][1])&quot; /&gt;

&lt;xsl:template match=&quot;/root&quot;&gt;
    &lt;xsl:copy&gt;
        &lt;xsl:copy-of select=&quot;key(&#39;r&#39;, &#39;&#39;)&quot;/&gt;
		&lt;xsl:for-each select=&quot;i[@type=&#39;s&#39;]&quot;&gt;
			&lt;xsl:variable name=&quot;r&quot; select=&quot;key(&#39;r&#39;, generate-id())&quot; /&gt;
			&lt;xsl:choose&gt;
				&lt;xsl:when test=&quot;$r&quot;&gt;
					&lt;wrap&gt;
						&lt;xsl:copy-of select=&quot;. | $r&quot;/&gt;
					&lt;/wrap&gt;
				&lt;/xsl:when&gt;
				&lt;xsl:otherwise&gt;
						&lt;xsl:copy-of select=&quot;.&quot;/&gt;
				&lt;/xsl:otherwise&gt;
			&lt;/xsl:choose&gt;
		&lt;/xsl:for-each&gt;
    &lt;/xsl:copy&gt;
&lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;

Result

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;root&gt;
   &lt;i type=&quot;r&quot;&gt;1&lt;/i&gt;
   &lt;wrap&gt;
      &lt;i type=&quot;s&quot;&gt;2&lt;/i&gt;
      &lt;i type=&quot;r&quot;&gt;3&lt;/i&gt;
      &lt;i type=&quot;r&quot;&gt;4&lt;/i&gt;
   &lt;/wrap&gt;
   &lt;wrap&gt;
      &lt;i type=&quot;s&quot;&gt;5&lt;/i&gt;
      &lt;i type=&quot;r&quot;&gt;6&lt;/i&gt;
   &lt;/wrap&gt;
   &lt;i type=&quot;s&quot;&gt;7&lt;/i&gt;
&lt;/root&gt;

答案2

得分: 0

这是一个双键方法。

<xsl:key name="r" match="i[@type = 'r']" use="generate-id(preceding-sibling::i[@type = 's'][1])"/>
<xsl:key name="s" match="i[@type = 's']" use="generate-id(following-sibling::i[@type = 'r'][1])"/>

<xsl:template match="i[@type = 's']">
<xsl:variable name="id" select="generate-id(.)"/>
xsl:choose

<xsl:when test="key('r', $id)">
<xsl:element name="wrap">
<xsl:copy-of select="."/>

<xsl:for-each select="key('r', $id)">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:element>
</xsl:when>
xsl:otherwise
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template match="i[@type = 'r']">
<xsl:variable name="id" select="generate-id(.)"/>

<xsl:if test="not(key('s', $id))">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>

<xsl:template match="node()">
<xsl:apply-templates select="node()"/>
</xsl:template>

英文:

Here is a two key approach.

&lt;xsl:key name=&quot;r&quot; match=&quot;i[@type = &#39;r&#39;]&quot; use=&quot;generate-id(preceding-sibling::i[@type = &#39;s&#39;][1])&quot;/&gt;
&lt;xsl:key name=&quot;s&quot; match=&quot;i[@type = &#39;s&#39;]&quot; use=&quot;generate-id(following-sibling::i[@type = &#39;r&#39;][1])&quot;/&gt;

&lt;xsl:template match=&quot;i[@type = &#39;s&#39;]&quot;&gt;
  &lt;xsl:variable name=&quot;id&quot; select=&quot;generate-id(.)&quot;/&gt;
  &lt;xsl:choose&gt;
    &lt;!-- Does this s have following r&#39;s?--&gt;
    &lt;xsl:when test=&quot;key(&#39;r&#39;, $id)&quot;&gt;
      &lt;xsl:element name=&quot;wrap&quot;&gt;
        &lt;xsl:copy-of select=&quot;.&quot;/&gt;
        &lt;!-- Output the r&#39;s that immedately follow this s. --&gt;
        &lt;xsl:for-each select=&quot;key(&#39;r&#39;, $id)&quot;&gt;
          &lt;xsl:copy-of select=&quot;.&quot;/&gt;  
        &lt;/xsl:for-each&gt;
      &lt;/xsl:element&gt;
    &lt;/xsl:when&gt;
    &lt;xsl:otherwise&gt;
      &lt;xsl:copy-of select=&quot;.&quot;/&gt;
    &lt;/xsl:otherwise&gt;
  &lt;/xsl:choose&gt;
&lt;/xsl:template&gt;

&lt;xsl:template match=&quot;i[@type = &#39;r&#39;]&quot;&gt;
  &lt;xsl:variable name=&quot;id&quot; select=&quot;generate-id(.)&quot;/&gt;
  &lt;!-- Only output r if it does not have a preceding s. --&gt;
  &lt;xsl:if test=&quot;not(key(&#39;s&#39;, $id))&quot;&gt;
    &lt;xsl:copy-of select=&quot;.&quot;/&gt;  
  &lt;/xsl:if&gt;
&lt;/xsl:template&gt;

&lt;!-- Create a template to walk through the nodes on the document. --&gt;
&lt;xsl:template match=&quot;node()&quot;&gt;
  &lt;xsl:apply-templates select=&quot;node()&quot;/&gt;
&lt;/xsl:template&gt;

huangapple
  • 本文由 发表于 2023年2月16日 19:44:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/75471782.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定