Не удается получить правильный вывод XSLT - PullRequest
2 голосов
/ 24 февраля 2012

У меня есть такой XML:

<?xml version="1.0" encoding="UTF-8"?>
<Section>
    <Chapter>
        <nametable>
            <namerow>
                <namecell stuff="1">
                    <entity>A</entity>
                </namecell>
                <namecell stuff="2">
                    <entity>B</entity>
                </namecell>
            </namerow>
        </nametable>
    </Chapter>
</Section>

Мой XSLT выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

<xsl:output method="text"/>

    <xsl:template match="/">
        <xsl:apply-templates select="Section/Chapter//nametable"/>
    </xsl:template>

    <xsl:template match="nametable">
        <xsl:for-each select="./namerow">
            <xsl:value-of select="./namecell/@stuff"/>
            <xsl:value-of select="./namecell" />
        </xsl:for-each>
    </xsl:template>

<xsl:template match="text()"/>

</xsl:stylesheet>

Странно, я получаю вывод в этом порядке 1 2 AB, Iдумал, что получу 1 A 2 B.

Не уверен, почему это так?

TIA,

Джон

Ответы [ 3 ]

3 голосов
/ 24 февраля 2012

Ваша проблема здесь :

        <xsl:for-each select="./namerow">
            <xsl:value-of select="./namecell/@stuff"/>
            <xsl:value-of select="./namecell" />
        </xsl:for-each>

В отличие от XSLT 1.0 в XSLT 2.0 команда xsl:value-of выводит все элементы последовательности, указанной в ееselect атрибут.

Это означает, что

<xsl:value-of select="./namecell/@stuff"/>

выводит все stuff атрибуты (1 и 2)

, затем следующая инструкция:

           <xsl:value-of select="./namecell" />

выводит строковое значение двух namecell дочерних элементов - соответственно "A" и "B".

Решение :

Заменить:

        <xsl:for-each select="./namerow">
            <xsl:value-of select="./namecell/@stuff"/>
            <xsl:value-of select="./namecell" />
        </xsl:for-each>

с :

        <xsl:for-each select="./namerow">
            <xsl:value-of select="./namecell/(@stuff|entity)"/>
        </xsl:for-each>

Полный код этой модификации: :

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

    <xsl:output method="text"/>

        <xsl:template match="/">
            <xsl:apply-templates select="Section/Chapter//nametable"/>
        </xsl:template>

        <xsl:template match="nametable">
            <xsl:for-each select="./namerow">
                <xsl:value-of select="./namecell/(@stuff|entity)"/>
            </xsl:for-each>
        </xsl:template>

    <xsl:template match="text()"/>
</xsl:stylesheet>

и когда это преобразование применяется к предоставленному XML-документу :

<Section>
    <Chapter>
        <nametable>
            <namerow>
                <namecell stuff="1">
                    <entity>A</entity>
                </namecell>
                <namecell stuff="2">
                    <entity>B</entity>
                </namecell>
            </namerow>
        </nametable>
    </Chapter>
</Section>

желаемый результат получается :

1 A 2 B

Второе решение (вероятно, то, что вы намеревались сделать в первую очередь):

Заменить :

    <xsl:template match="nametable">
        <xsl:for-each select="./namerow">
            <xsl:value-of select="./namecell/@stuff"/>
            <xsl:value-of select="./namecell" />
        </xsl:for-each>
    </xsl:template>

на :

    <xsl:template match="nametable">
        <xsl:for-each select="namerow/namecell">
            <xsl:value-of select="@stuff"/>
            <xsl:value-of select="entity"/>
        </xsl:for-each>
    </xsl:template>

Теперь вы снова получите желаемый результатlt :

1A2B
1 голос
/ 24 февраля 2012

Причина поведения, которое вы видите, состоит в том, что вы перебираете имя. Вы получите 1A2B, если вместо этого будете выполнять итерацию по имени: <xsl:for-each select="namerow/namecell"><xsl:value-of select="@stuff"/><xsl:value-of select="." /></xsl:for-each>. Вы должны помнить, что каждый XPath, такой как @stuff, дает вам не обязательно одно значение (узел), а скорее набор значений (набор узлов). Этот набор обычно содержит только одно значение, но не обманывайте себя.

Другой синтаксис для той же вещи: <xsl:for-each select="namerow"><xsl:for-each select="namecell"><xsl:value-of select="@stuff"/><xsl:value-of select="." /></xsl:for-each></xsl:for-each>

P.S. Как и в пути к файловой системе, вам не нужно писать «./» перед XPath.

1 голос
/ 24 февраля 2012

Я использую msxml, получаю 1 A как оп: |

Ну вот решение для вас, оно работает как драгоценный камень:)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

  <xsl:output method="text"/>

  <xsl:template match="/Section/Chapter/nametable/namerow/namecell">
    <xsl:value-of select="@stuff"/>
    <xsl:text> </xsl:text><!--inserting a space-->
    <xsl:value-of select="entity"/>
    <xsl:text> </xsl:text><!--inserting a space-->
  </xsl:template>
  <xsl:template match="text()"/>

</xsl:stylesheet>
...