【问题标题】:Can't get correct XSLT output无法获得正确的 XSLT 输出
【发布时间】:2012-02-24 03:59:41
【问题描述】:

我有一个这样的 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 A B,我以为我会得到 1 A 2 B。

不知道为什么?

TIA,

约翰

【问题讨论】:

    标签: xslt xslt-2.0 xpath-2.0


    【解决方案1】:

    你的问题就在这里

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

    与 XSLT 2.0 中的 XSLT 1.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>
    

    现在你又得到了想要的结果

    1A2B
    

    【讨论】:

    • Dimitri:这个 真的是做什么的?。
    • @JohnX: &lt;xsl:value-of select="./namecell/(@stuff|entity)"/&gt; 将每个stuff 属性的字符串值和当前节点的每个namecell 子节点的entity 子节点的字符串值输出为文本节点。这里我使用 Xpath union 运算符|。只有在 XPath 2.0 中才能在定位步骤中进行这种联合——在 XPath 1.0 中语法上是非法的。
    • Dimitre:还有一些问题stackoverflow.com/questions/9448446/…。谢谢!。
    【解决方案2】:

    我正在使用 msxml,得到1 A 作为操作:|

    这是一个适合你的解决方案,它就像 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>
    

    【讨论】:

    • 这就是我为得到正确答案所做的,我正在使用 Saxon EE,但我不明白为什么我的原始帖子无法正常工作?。
    • 这可能是因为您使用的是/namecell/@stuff 而不是/@stuff .. 我并没有真正专注于 xslt 2.0 所以不确定..
    • msxml 不允许:/ N 我的工具背景编码基于.net :(
    【解决方案3】:

    您看到的行为的原因是您对 namerow 进行了迭代。如果您将 namecell 迭代为:&lt;xsl:for-each select="namerow/namecell"&gt;&lt;xsl:value-of select="@stuff"/&gt;&lt;xsl:value-of select="." /&gt;&lt;/xsl:for-each&gt;,您将获得 1A2B。您需要记住,每个 XPath(例如 @stuff)不一定给您一个值(一个节点),而是一组值(一个节点集)。该集合通常只包含一个值,但不要上当。

    同一事物的另一种语法:&lt;xsl:for-each select="namerow"&gt;&lt;xsl:for-each select="namecell"&gt;&lt;xsl:value-of select="@stuff"/&gt;&lt;xsl:value-of select="." /&gt;&lt;/xsl:for-each&gt;&lt;/xsl:for-each&gt;

    附:就像在文件系统路径中一样,您不必在 XPath 之前写“./”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-09
      • 1970-01-01
      • 2020-12-03
      • 1970-01-01
      • 2012-03-16
      • 2011-12-27
      相关资源
      最近更新 更多