XSLT:如何使用变量作为查找来更新节点

时间:2013-08-23 07:31:45

标签: xml xslt xslt-1.0 lookup

这是我的source.xml:

<entries>
    <entry path="/folder/abc.txt">
        <a>abc</a>
        <b>baz</b>
    </entry>
    <entry path="/other/def.txt">
        <a>foo</a>
        <b>bar</b>
    </entry>    
</entries>

我的XSLT看起来像:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
    <xsl:variable name="lookup">
        <pair>
            <key>/folder/abc.txt</key>
            <value>/other/folder/abc.txt</value>
        </pair>
        <pair>
            <key>/other/def.txt</key>
            <value>/other/folder/misc/def.txt</value>
        </pair>
    </xsl:variable>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

因此我可以重现我的源xml。我想要的是使用变量path更新lookup(其中path应与key匹配,以返回value)。

最终输出将是:

<entries>
    <entry path="/other/folder/abc.txt">
        <a>abc</a>
        <b>baz</b>
    </entry>
    <entry path="/other/folder/misc/def.txt">
        <a>foo</a>
        <b>bar</b>
    </entry>    
</entries>

最新的要求是完全保留缩进。

我怎样才能做到这一点?

提前致谢。

2 个答案:

答案 0 :(得分:2)

以下XSL模板应该这样做。它使用EXSLT扩展函数将您的变量转换为节点集。 (警告:如果变量中的路径不匹配,则路径将被删除!)

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

  <xsl:variable name="lookup">
    <pair>
      <key>/folder/abc.txt</key>
      <value>/other/folder/abc.txt</value>
    </pair>
    <pair>
      <key>/other/def.txt</key>
      <value>/other/folder/misc/def.txt</value>
    </pair>
  </xsl:variable>

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

  <xsl:template match="entry">
    <xsl:copy>
      <xsl:attribute name="path">
        <xsl:call-template name="replace">
          <xsl:with-param name="input" select="@path"/>
        </xsl:call-template>
      </xsl:attribute>
      <xsl:apply-templates select="*"/>
    </xsl:copy>
  </xsl:template>

  <!-- This template looks through each pair in lookup, finds the one whose
       key matches the input and returns the corresponding value. If none
       match, nothing will be returned. -->    
  <xsl:template name="replace">
    <xsl:param name="input"/>
    <xsl:for-each select="exslt:node-set($lookup)/pair">
        <xsl:if test="key = $input">
          <xsl:value-of select="value"/>
        </xsl:if>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

您可以看到它正常工作here

答案 1 :(得分:1)

您可以将查找放在单独的文件中,并通过重新排列来简化:

<强> lookup.xml:

<entries>
    <entry path="/folder/abc.txt">/other/folder/abc.txt</entry>
    <entry path="/other/def.txt">/other/folder/misc/def.txt</entry>
</entries>

你的xslt:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />

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


    <xsl:template match="entry/@path">
        <xsl:variable name="oldpath" select="." />
        <xsl:attribute name="path"><xsl:value-of
            select="document('lookup.xml')/entries/entry[@path = $oldpath]" /></xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

请注意,如果没有匹配项,解决方案将不会保留原始值。