Can't get correct XSLT output

霸气de小男生 提交于 2020-01-04 15:27:28

问题


I have a XML like this:

<?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>

My XSLT is like this:

<?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>

Odd is I'm getting an output in this order 1 2 A B, I thought I'm going to get 1 A 2 B.

Not sure why is that ?.

TIA,

John


回答1:


Your problem is here:

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

Unlike in XSLT 1.0 in XSLT 2.0 the xsl:value-of instruction outputs all items of the sequence specified in its select attribute.

This means that

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

outputs all stuff attributes (1 and 2)

then the next instruction:

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

outputs the string value of the two namecell children -- respectively "A" and "B".

Solution:

Replace:

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

with:

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

The complete code with this modification is:

<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>

and when this transformation is applied on the provided XML document:

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

the wanted result is produced:

1 A 2 B

Second solution (probably what you intended to do in the first place):

Replace:

    <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>

with:

    <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>

Now you again get the wanted result:

1A2B



回答2:


I am using msxml, am getting 1 A as op :|

Well here is a solution for you it works like gem :)

<?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>



回答3:


The reason for the behavior you see is that you iterate over namerow. You will get 1A2B if you will instead iterate over namecell as: <xsl:for-each select="namerow/namecell"><xsl:value-of select="@stuff"/><xsl:value-of select="." /></xsl:for-each>. You'll want to remember that each XPath such as @stuff gives you not necessarily one value (a node), but rather a set of values (a nodeset). That set will commonly happen to contain only one value, but don't be fooled.

Another syntax for the same thing: <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. Just as in a filesystem path, you don't have to write "./" before an XPath.



来源:https://stackoverflow.com/questions/9425190/cant-get-correct-xslt-output

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!