2

我有一个 xsl:template 将一个附加节点插入到我的原始 XML 中。

然后,我想使用以下模板来引用该新节点,以帮助继续解析源文件。

我当前的方法(第二个模板)没有“看到”第一个模板中新插入的节点。我将如何处理这个?

非常感谢。

下面的示例非常简化,以表达我想要实现的目标。

启动 XML:

<master> 
 <node>
  <node1>hi</node1>
  <node2>bye</node2>
 </node>
</master>

第一个模板:

<xsl:template match="master/node">
  <node>
  <xsl:apply-templates/>
  <node3>greetings</node3>
  </node>
</xsl:template>

结果 XML 1:

<master> 
 <node>
  <node1>hi</node1>
  <node2>bye</node2>
  <node3>greetings<node3>
 </node>
</master>

第二个模板:

<xsl:template match="master/node[node3='greetings']">
  <node>
   <newnode><xsl:value-of select="./node3"/>
  </node>
</xsl:template>

预期结果:

<master> 
 <node>
  <newnode>greetings</newnode>
 </node>
</master>

XSL:

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

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

        <!-- first template -->
<xsl:template match="master/node">
  <node>
  <xsl:apply-templates/>
  <node3>greetings</node3>
  </node>
</xsl:template>

        <!-- second template -->
<xsl:template match="master/node[node3='greetings']">
  <node>
   <newnode><xsl:value-of select="./node3"/></newnode>
  </node>
</xsl:template>

4

3 回答 3

3

在没有扩展的 XSLT 1.0 中,只有输入文档中的节点可以被模板匹配。要将模板应用于中间结果,您可以使用nodeset允许将模板应用于结果树片段的扩展(由 XSLT 1.0 实现广泛实现)。或者,您可以迁移到 XSLT 2.0。

有关节点集扩展的更多详细信息,请参阅Dimitre Novatchev 对相关问题的回答

于 2012-09-11T01:57:55.610 回答
1

Michael Sperberg-McQueen 给出了如何在 XSLT 1.0 中处理 RTF(结果树片段)的精确解释。

node-set()以下是使用 EXSLT扩展功能的完整解决方案示例:

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

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

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
   <xsl:apply-templates/>
  </xsl:variable>
  <xsl:apply-templates select="ext:node-set($vrtfPass1)/*"/>
 </xsl:template>

 <xsl:template match="master/node">
  <node>
   <xsl:apply-templates/>
   <node3>greetings</node3>
  </node>
 </xsl:template>

 <xsl:template match="master/node[node3='greetings']" priority="2">
  <node>
   <newnode><xsl:value-of select="./node3"/></newnode>
  </node>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<master>
 <node>
  <node1>hi</node1>
  <node2>bye</node2>
 </node>
</master>

产生了想要的正确结果:

<master>
   <node>
      <newnode>greetings</newnode>
   </node>
</master>

请注意,最好以这样的方式组织多通道处理,即在 Pass-N 中运行的所有模板都处于与在任何其他通道号中运行的所有模板不同的模式。这是为了避免在 Pass-N 和 Pass-M 中意外选择执行相同的模板时出错。

使用模式,上述解决方案变为

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

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

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

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
   <xsl:apply-templates/>
  </xsl:variable>
  <xsl:apply-templates mode="pass2"
  select="ext:node-set($vrtfPass1)/*"/>
 </xsl:template>

 <xsl:template match="master/node">
  <node>
   <xsl:apply-templates/>
   <node3>greetings</node3>
  </node>
 </xsl:template>

 <xsl:template mode="pass2" match="master/node[node3='greetings']"
      priority="2">
  <node>
   <newnode><xsl:value-of select="./node3"/></newnode>
  </node>
 </xsl:template>
</xsl:stylesheet>
于 2012-09-11T04:19:39.063 回答
1

在 XSLT 2.0 中,您只需将第一个模板的输出捕获到一个变量中,该变量的值是一个新的 XML 文档,可以像源文档一样进行处理。

在 XSLT 1.0 中,当您在变量中捕获模板的输出时,它不是一流的文档,而是只能以非常有限的方式处理的“结果树片段”。exslt:node-set() 扩展将其从“结果树片段”转换为可以正常处理的一流文档。

我希望这有助于总结其他人提供的非常详细的信息(尽管我确实觉得这些天,我们应该假设人们正在使用 XSLT 2.0,除非他们另有说明)。

于 2012-09-11T08:02:54.700 回答