在XSLT中将XML兄弟标签包裹在一个父标签中

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

Wrap XML sibling tags in a parent tag with XSLT

问题

I have a set of sibling tags that look like this in a much larger document:

<?xml version="1.0" encoding="UTF-8"?>
<foo>
  <a>some text</a>, '<b>some text</b>', <c><d>some text</d> <e>sometext</e></c>
</foo>

The requirement is that the transform matches tag a followed by ",", followed by tag b, then tag c. These are then wrapped in an outer tag. Below is a simplified representation of what I would like the document to look like:

<?xml version="1.0" encoding="UTF-8"?>
<foo>
  <bar><a>some text</a>, '<b>some text</b>', <c><d>some text</d> <e>sometext</e></c></bar>
</foo>

However, I want this to be done in place in a much larger document without disturbing any other tags.

Basically, I am attempting to match the pattern above in the nodes in the document, then wrap the pattern in a parent tag and delete the old nodes so I do not have duplicates in the output. Is there a way to do that cleanly in XSLT?

英文:

I have a set of sibling tags that look like this in a much larger document:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;foo&gt;
  &lt;a&gt;some text&lt;/a&gt;, &#39;&lt;b&gt;some text&lt;/b&gt;&#39;, &lt;c&gt;&lt;d&gt;some text&lt;/d&gt; &lt;e&gt;sometext&lt;/e&gt;&lt;/c&gt;
&lt;/foo&gt;

The requirement is that the transform matches tag a followed by "," followed by tag b, then tag c. These are then wrapped in an outer tag. Below is a simplified representation of what I would like the document to look like:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;foo&gt;
  &lt;bar&gt;&lt;a&gt;some text&lt;/a&gt;, `&lt;b&gt;some text&lt;/b&gt;&#39;, &lt;c&gt;&lt;d&gt;some text&lt;/d&gt; &lt;e&gt;sometext&lt;/e&gt;&lt;/c&gt;&lt;/bar&gt;
&lt;/foo&gt;

However, I want this to be done in place in a much larger document without disturbing any other tags.

Basically, I am attempting to match the pattern above in the nodes in the document then wrap the pattern in a parent tag and delete the old nodes so I do not have duplicates in the output. Is there away to do that cleanly in XSLT?

答案1

得分: 0

这是一个有点奇怪的序列,所以我能够得出的答案是一种有点奇怪的组合,使用了for-each-group group-starting-withfor-each-group group-adjacent(将检查委托给一个函数,你可能需要调整该函数以确切地检查你的节点是否符合预期):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="#all"
    version="3.0">
  
  <xsl:function name="mf:adjacent-predicate" as="xs:boolean">
    <xsl:param name="node" as="node()"/>
    <xsl:param name="pos" as="xs:integer"/>
    <xsl:sequence
      select="$pos eq 1 and $node instance of element(a) or
              $pos = (2,4) and $node instance of text() and contains($node, ',') or
              $pos eq 3 and $node instance of element(b) or
              $pos eq 5 and $node instance of element(c)"/>
  </xsl:function>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="*[a]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:for-each-group select="node()" group-starting-with="a">
        <xsl:choose>
          <xsl:when test="self::a">
            <xsl:for-each-group select="current-group()" group-adjacent="mf:adjacent-predicate(., position())">
              <xsl:choose>
                <xsl:when test="current-grouping-key()">
                  <bar>
                    <xsl:apply-templates select="current-group()"/>
                  </bar>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:apply-templates select="current-group()"/>
                </xsl:otherwise>          
              </xsl:choose>
            </xsl:for-each-group>
          </xsl:when>
          <xsl:otherwise>
            <xsl:apply-templates select="current-group()"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>
英文:

It is kind of an odd sequence so all I have been able to come with is a bit of an odd combination of a for-each-group group-starting-with plus for-each-group group-adjacent (delegating the check to a function you probably need to adjust to check your nodes exactly as you expect them):

&lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
	xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot;
	xmlns:mf=&quot;http://example.com/mf&quot;
	exclude-result-prefixes=&quot;#all&quot;
	version=&quot;3.0&quot;&gt;
  
  &lt;xsl:function name=&quot;mf:adjacent-predicate&quot; as=&quot;xs:boolean&quot;&gt;
    &lt;xsl:param name=&quot;node&quot; as=&quot;node()&quot;/&gt;
    &lt;xsl:param name=&quot;pos&quot; as=&quot;xs:integer&quot;/&gt;
    &lt;xsl:sequence
      select=&quot;$pos eq 1 and $node instance of element(a) or
              $pos = (2,4) and $node instance of text() and contains($node, &#39;,&#39;) or
              $pos eq 3 and $node instance of element(b) or
              $pos eq 5 and $node instance of element(c)&quot;/&gt;
  &lt;/xsl:function&gt;

  &lt;xsl:mode on-no-match=&quot;shallow-copy&quot;/&gt;

  &lt;xsl:template match=&quot;*[a]&quot;&gt;
    &lt;xsl:copy&gt;
      &lt;xsl:apply-templates select=&quot;@*&quot;/&gt;
      &lt;xsl:for-each-group select=&quot;node()&quot; group-starting-with=&quot;a&quot;&gt;
        &lt;xsl:choose&gt;
          &lt;xsl:when test=&quot;self::a&quot;&gt;
            &lt;xsl:for-each-group select=&quot;current-group()&quot; group-adjacent=&quot;mf:adjacent-predicate(., position())&quot;&gt;
              &lt;xsl:choose&gt;
                &lt;xsl:when test=&quot;current-grouping-key()&quot;&gt;
                  &lt;bar&gt;
                    &lt;xsl:apply-templates select=&quot;current-group()&quot;/&gt;
                  &lt;/bar&gt;
                &lt;/xsl:when&gt;
                &lt;xsl:otherwise&gt;
                  &lt;xsl:apply-templates select=&quot;current-group()&quot;/&gt;
                &lt;/xsl:otherwise&gt;          
              &lt;/xsl:choose&gt;
            &lt;/xsl:for-each-group&gt;
          &lt;/xsl:when&gt;
          &lt;xsl:otherwise&gt;
            &lt;xsl:apply-templates select=&quot;current-group()&quot;/&gt;
          &lt;/xsl:otherwise&gt;
        &lt;/xsl:choose&gt;
      &lt;/xsl:for-each-group&gt;
    &lt;/xsl:copy&gt;
  &lt;/xsl:template&gt;
  
&lt;/xsl:stylesheet&gt;

huangapple
  • 本文由 发表于 2023年2月24日 04:30:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/75550015.html
匿名

发表评论

匿名网友

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

确定