// <node>не дает все совпадающие узлы - PullRequest
3 голосов
/ 20 января 2012

С учетом следующего 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 ]

4 голосов
/ 20 января 2012

Рассмотрим ваш первый шаблон…

<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 голос
/ 21 января 2012

Ваша ошибка состоит в том, что, поскольку шаблон с match = "// StepFusion" соответствует каждому элементу StepFusion, он будет вызываться для обработки каждого элемента StepFusion.Фактически, он будет обрабатывать только те элементы StepFusion, которые были выбраны для обработки с помощью инструкции xsl: apply-templates.

Я подозреваю, что такого рода путаница часто существует, когда люди используют match '"// StepFusion"вместо более простого и понятного соответствия = "StepFusion".Атрибут match проверяет, может ли данный элемент обрабатываться этим правилом шаблона;это инструкция apply-templates, которая решает, какие элементы отправить в этот тест.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...