在XSLT中基于单个子值复制整个节点

时间:2010-12-15 17:52:58

标签: xml xslt

我有两个文件,并希望根据节点树中的特定匹配值来组合/覆盖整个节点。

file1.xml

  <record>
    <key>key1</key>
    <nodel>
      <field1>source field1</field1>
      <field2>source field2</field2>
      <searchkey>myname</searchkey>
    </nodel>
  </record>

file2.xml

  <record>
    <key>key2</key>
    <nodel>
      <field1>match field1</field1>
      <field2>match field2</field2>
      <searchkey>myname</searchkey>
    </nodel>
  </record>

期望的输出:

  <record>
    <key>key1</key>
    <nodel>
      <field1>source field1</field1>
      <field2>source field2</field2>
      <searchkey>myname</searchkey>
    </nodel>

    <nodel>
      <field1>match field1</field1>
      <field2>match field2</field2>
      <searchkey>myname</searchkey>
    </nodel>
  </record>

所以,我想在两个文件之间的searchkey中检查匹配,如果匹配,则将匹配的整个节点复制到输出文件,但保留原始密钥,而不是匹配密钥。然后,我将删除原始nodel,但我很乐意将其作为后续转换。

我确实询问了最近在<key>节点上进行匹配的类似问题,但无法弄清楚如何修改它以实现所需的结果。

感谢。

3 个答案:

答案 0 :(得分:1)

此转化

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

 <my:file2>
  <record>
    <key>key2</key>
    <nodel>
      <field1>match field1</field1>
      <field2>match field2</field2>
      <searchkey>myname</searchkey>
    </nodel>
  </record>
 </my:file2>

 <xsl:variable name="vFile2"
      select="document('')/*/my:file2/*"/>

 <xsl:template match="node()|@*" name="identity">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="/*/*[starts-with(name(),'node')]">
  <xsl:call-template name="identity"/>
  <xsl:apply-templates mode="copy" select=
   "$vFile2/*[starts-with(name(),'node')]
                  [searchkey=current()/searchkey]
   "/>
 </xsl:template>

 <xsl:template match="node()" mode="copy">
  <xsl:call-template name="identity"/>
 </xsl:template>
</xsl:stylesheet>

应用于提供的第一个XML文档

<record>
    <key>key1</key>
    <nodel>
        <field1>source field1</field1>
        <field2>source field2</field2>
        <searchkey>myname</searchkey>
    </nodel>
</record>

会产生想要的正确结果:

<record>
   <key>key1</key>
   <nodel>
      <field1>source field1</field1>
      <field2>source field2</field2>
      <searchkey>myname</searchkey>
   </nodel>
   <nodel>
      <field1>match field1</field1>
      <field2>match field2</field2>
      <searchkey>myname</searchkey>
   </nodel>
</record>

注意:第二个XML文档在样式表中以内联方式表示 - 这只是为了方便起见。实际上,它将驻留在自己的文件中,只有$vFile2的定义将更改为:

 <xsl:variable name="vFile2"
      select="document('someFileURIHere')/*"/>

答案 1 :(得分:1)

带密钥的解决方案:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kNodeBySearchkey" match="*[searchkey]" use="searchkey"/>
    <xsl:param name="pSource2" select="'file2.xml'"/>
    <xsl:variable name="vSource2" select="document($pSource2,/)"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[searchkey]">
        <xsl:variable name="vKey" select="searchkey"/>
        <xsl:call-template name="identity"/>
        <xsl:for-each select="$vSource2">
            <xsl:for-each select="key('kNodeBySearchkey',$vKey)">
                <xsl:call-template name="identity"/>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

输出:

<record>
    <key>key1</key>
    <nodel>
        <field1>source field1</field1>
        <field2>source field2</field2>
        <searchkey>myname</searchkey>
    </nodel>
    <nodel>
        <field1>source field1</field1>
        <field2>source field2</field2>
        <searchkey>myname</searchkey>
    </nodel>
</record>

注意:我不想保留原始nodel,只需删除第一条xsl:call-template指令。

答案 2 :(得分:0)

尝试输入文件名:

XSL

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
    <xsl:param name="pSource2" select="'file2.xml'"/>
    <xsl:variable name="vFile2" select="document($pSource2)/*"/>

 <xsl:template match="node()|@*" name="identity">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="/*/*[starts-with(name(),'node')]">
  <xsl:call-template name="identity"/>
  <xsl:apply-templates select=
   "$vFile2/*[starts-with(name(),'node')]
                  [searchkey=current()/searchkey]
   "/>
 </xsl:template>
</xsl:stylesheet>

给予

<record>
<key>key1</key>
<nodel>
<field1>source field1</field1>
<field2>source field2</field2>
<searchkey>myname</searchkey>
</nodel>
<nodel>
<field1>match field1</field1>
<field2>match field2</field2>
<searchkey>myname</searchkey>
</nodel>

重复第二个节点直到它放弃。