在XSLT中,是否可以跟踪路径并动态使用它?

时间:2013-05-22 09:28:57

标签: xslt dynamic path

昨天我问a question有关从XSLT动态加载外部XML的问题。它得到了答复,但现在我有另一个问题。如果您阅读该问题,您会在第三级看到<include ref="/path/to/some.xml" />。如果<include>发生的级别变化怎么办?

有没有办法动态选择从原始文件中出现的相同级别的XML中提取节点?

修改 要明确:我在谈论XML中的“元素路径”(XML中include元素的位置),而不是文件路径。

merge.xslt:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >

  <xsl:output indent="yes" method="xml" encoding="utf-8"
    omit-xml-declaration="yes" />

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

  <xsl:template match="include">
      <!-- the depth of the extraction path (fruit/*/*/*... etc) should
           be based on the position of the matched <include> element -->
      <xsl:apply-templates select="document(@ref)/fruit/*/*/*"/>
  </xsl:template>
</xsl:stylesheet>

fruit.xml:

<fruit>
  <local>
    <apples>
      <include ref="apples.xml" />
    </apples>
  </local>
  <exotic>
    <bananas>
      <deeperlevel>
        <include ref="bananas.xml" />
      </deeperlevel>
    </bananas>
    <oranges>
      <include ref="oranges.xml" />
    </oranges>
  </exotic>
</fruit>

bananans.xml:

<fruit>
  <exotic>
    <bananas>
      <deeperlevel>
        <banana type="chiquita" color="yellow" />
        <banana type="generic" color="yellow" />
      </deeperlevel>
    </bananas>
  </exotic>
</fruit>

结果:

<fruit>
  <local>
    <apples>
      <apple type="jonagold" color="red"/><apple type="granny-smith" color="green"/>
    </apples>
  </local>
  <exotic>
    <bananas>
      <deeperlevel>
        <deeperlevel> <!-- I don't want the second <deeperlevel> here, instead
                           <bananas .../> should be extracted, right after the
                           first <deeperlevel> -->
          <banana type="chiquita" color="yellow"/>
          <banana type="generic" color="yellow"/>
        </deeperlevel>
      </deeperlevel>
    </bananas>
    <oranges>
      <orange type="juice-orange" color="orange"/><orange type="red-orange" color="red"/>
    </oranges>
  </exotic>
</fruit>

1 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法。它不是非常好的恕我直言,因为它是一个“eval”型解决方案,但它的工作原理。我在this question的答案中对我的问题,动态XPath评估扩展(dyn:evaluate())应用了第3个建议。幸运的是xsltproc库中的libxslt工具(通过macports 1.1.27安装)支持它。

我会暂时搁置这个问题,也许某人有更好的解决方案。

XSLT:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:dyn="http://exslt.org/dynamic"
  extension-element-prefixes="dyn">

  <xsl:output indent="yes" method="xml" encoding="utf-8"
    omit-xml-declaration="yes" />

  <xsl:template match="@*|node()">
    <xsl:param name="depth" select="'/*'" />
    <xsl:copy>
      <xsl:apply-templates select="@*|node()">
        <xsl:with-param name="depth" select="concat($depth, '/*')" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="include">
    <xsl:param name="depth" />
    <xsl:apply-templates select="dyn:evaluate(concat('document(@ref)', $depth))">
      <xsl:with-param name="depth" select="$depth" />
    </xsl:apply-templates>
  </xsl:template>

</xsl:stylesheet>