基于 XPATH 创建 XML 个节点

Creating XML nodes based on XPATH

我需要使用 XPATH 添加 XML 个节点。我从 Whosebug 中的另一个线程得到了下面的 XSLT,它完成了这项工作。 但我面临一个问题,如果我们不维护 XSLT 中 XPATH 的顺序,那么它会多次创建相同的 XML 标签。请参考下面的示例 XML 和 XSLT 以更好地理解它。请帮助解决这个问题。

输入XML:

<header>
  <txCtry>SG</txCtry>
  <msgId>b626c6be4a724f8aa92dcba1b4e07cf0</msgId>
</header>
<data>
  <txCtry>SG</txCtry>
  <txCityCd>SIN</txCityCd>
</data>

XSLT:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vPop" as="element()*">
<item path="/header/txCtryyyy">F</item>
<item path="/header/btchBookg">ddddddddddddd</item>
<item path="/data/txSttlmInf/instgRmbrsmntAgt/BICFIIIIII">FXZ9200136548878</item>
<item path="/header/prcgSubSts">ooooooooooooooo</item>
 </xsl:variable>

 <xsl:template match="/">
  <xsl:sequence select="my:subTree($vPop/@path/concat(.,'/',string(..)))"/>
 </xsl:template>

 <xsl:function name="my:subTree" as="node()*">
  <xsl:param name="pPaths" as="xs:string*"/>

  <xsl:for-each-group select="$pPaths"
    group-adjacent=
        "substring-before(substring-after(concat(., '/'), '/'), '/')">
    <xsl:if test="current-grouping-key()">
     <xsl:choose>
       <xsl:when test=
          "substring-after(current-group()[1], current-grouping-key())">
         <xsl:element name=
           "{substring-before(concat(current-grouping-key(), '['), '[')}">

          <xsl:sequence select=
            "my:subTree(for $s in current-group()
                         return
                            concat('/',substring-after(substring($s, 2),'/'))
                             )
            "/>
        </xsl:element>
       </xsl:when>
       <xsl:otherwise>
        <xsl:value-of select="current-grouping-key()"/>
       </xsl:otherwise>
     </xsl:choose>
     </xsl:if>
  </xsl:for-each-group>
 </xsl:function>
</xsl:stylesheet>

已转换 XML:

<header>
   <txCtryyyy>F</txCtryyyy>
</header>
<data>
   <txSttlmInf>
      <instgRmbrsmntAgt>
         <BICFIIIIII>FXZ9200136548878</BICFIIIIII>
      </instgRmbrsmntAgt>
   </txSttlmInf>
</data>
<header>
   <btchBookg>ddddddddddddd</btchBookg>
</header>
<data>
   <txSttlmInf>
      <instgRmbrsmntAgt>
         <BICFHHHH>FXZ92001365kkkkkkkk48878</BICFHHHH>
      </instgRmbrsmntAgt>
   </txSttlmInf>
</data>
<header>
   <prcgSubSts>ooooooooooooooo</prcgSubSts>
</header>

在这里我们可以看到 header 和数据标签被多次创建。

预期输出:

<header>
   <txCtryyyy>F</txCtryyyy>
   <btchBookg>ddddddddddddd</btchBookg>
   <prcgSubSts>ooooooooooooooo</prcgSubSts>
</header>
<data>
   <txSttlmInf>
      <instgRmbrsmntAgt>
         <BICFIIIIII>FXZ9200136548878</BICFIIIIII>
         <BICFHHHH>FXZ92001365kkkkkkkk48878</BICFHHHH>
      </instgRmbrsmntAgt>
   </txSttlmInf>
</data>

尝试在你有 <xsl:for-each-group select="$pPaths" group-adjacent="substring-before(substring-after(concat(., '/'), '/'), '/')"> 的函数中使用 group-by 而不是 group-adjacent,尝试使用 <xsl:for-each-group select="$pPaths" group-by="substring-before(substring-after(concat(., '/'), '/'), '/')">.