// <node>不提供与</node>匹配的所有节点

时间:2012-01-20 19:17:18

标签: c# xslt

给出以下XML:

<root>
  <StepFusionSet name="SF1">
      <StepFusionSet name="SF2">
      </StepFusionSet>
  </StepFusionSet>
  <StepFusionSet name="SF10">
  </StepFusionSet>
</root>

以下C#代码:

        XPathDocument doc = new XPathDocument("input.xml");
        var nav = doc.CreateNavigator();

        var item = nav.Select("//StepFusionSet[@name]");
        while (item.MoveNext())
        {
            Debug.WriteLine(item.Current.GetAttribute("name", item.Current.NamespaceURI));
        }

给我输出:

SF1
SF2
SF10

但是以下XSLT文件:

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

  <xsl:template match="//StepFusionSet">
    <xsl:call-template name="a"/>
  </xsl:template>

  <xsl:template name="a">
      <xsl:apply-templates select="@name"/>
  </xsl:template>
</xsl:stylesheet>

(由C#代码调用:)

        XslTransform xslt = new XslTransform();
        xslt.Load("transform.xslt");
        XPathDocument doc = new XPathDocument("input.xml");
        MemoryStream ms = new MemoryStream();

        xslt.Transform(doc, null, ms);

给我输出:

SF1
SF10

我在XSLT文件中做错了什么?

2 个答案:

答案 0 :(得分:4)

考虑你的第一个模板......

<xsl:template match="//StepFusionSet">

...适用于您的SF1和(嵌套)SF2元素:

<StepFusionSet name="SF1">
  <StepFusionSet name="SF2">
  </StepFusionSet>
</StepFusionSet>

模板与您的外SF1元素匹配;但是,然后需要将其重新应用于匹配元素的子元素,以匹配您的内部SF2

这可以通过在第二个模板定义中嵌入递归<xsl:apply-templates/>来实现:

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

  <xsl:template match="//StepFusionSet">
    <xsl:call-template name="a"/>
  </xsl:template>

  <xsl:template name="a">
    <xsl:apply-templates select="@name"/>
    <xsl:apply-templates/>
  </xsl:template>

</xsl:stylesheet>

或者,您可以使用<xsl:for-each>元素选择所有<StepFusionSet>元素(包括嵌套的元素,例如SF2):

<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/">
    <xsl:for-each select="//StepFusionSet">
      <xsl:value-of select="@name"/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

你的错误是假设因为带有match =“// StepFusion”的模板匹配每个StepFusion元素,因此将调用它来处理每个StepFusion元素。实际上,它只会处理那些已被xsl:apply-templates指令选中进行处理的StepFusion元素。

我怀疑这种混淆经常存在于人们使用匹配'“// StepFusion”而不是更简单和更清晰的匹配=“StepFusion”。 match属性测试给定元素是否有资格通过此模板规则进行处理;它是apply-templates指令,用于决定提交给此测试的元素。