【问题标题】:Output values in a certain way using XSLT/XPath 2.0使用 XSLT/XPath 2.0 以某种方式输出值
【发布时间】:2012-03-15 22:44:42
【问题描述】:

我有一个这样的 XML:

<?xml version="1.0" encoding="UTF-8"?>

<Section>
    <Chapter>
        <Cell colname="1">
            <Value>A</Value>
        </Cell>
        <Cell colname="2">
            <MyValue>AAA</MyValue>
            <MyValue>BBB</MyValue>
        </Cell>
        <Cell colname="3">
            <MyCar>Honda</MyCar>
        </Cell>
    </Chapter>
    <Chapter>
        <Cell colname="1">
            <Value>C</Value>
        </Cell>
        <Cell colname="2">
            <MyValue>CCC</MyValue>
        </Cell>
        <Cell colname="3">
            <MyCar>Toyota</MyCar>
        </Cell>
    </Chapter>
</Section>

我喜欢这样的消息(稍后将它们转换为标签)输出:

一个 AAA 本田 一种 BBB 本田 C CCC 丰田

这是我的 XSLT:

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

    <xsl:output method="xml" version="1.0" encoding="iso-8859-1"   indent="yes"/>

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

    <xsl:template match="Chapter">
        <xsl:for-each select="Cell[@colname='2']//MyValue">
            <xsl:message>
                <xsl:value-of select="Cell[@colname='1']/Value"/>
                <xsl:value-of select="."/>
                <xsl:value-of select="Cell[@colname='3']/MyCar"/>
            </xsl:message>
        </xsl:for-each>
    </xsl:template>

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

</xsl:stylesheet>

不幸的是,它没有输出我想要它做的事情:(。

我意识到 for-each 会改变上下文,所以剩余的 value-ofs 不会做任何事情。

对此有什么解决方案?

TIA,

约翰

【问题讨论】:

    标签: xslt xslt-2.0 xpath-2.0


    【解决方案1】:

    这个 XSLT 2.0 转换(等效的 XSLT 1.0 转换可以从这个机械地写出来)。

    请注意:这是一个通用解决方案,适用于任意数量的孩子,不依赖硬编码的名称。

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:template match="Chapter">
      <xsl:apply-templates select="Cell[1]"/>
     </xsl:template>
    
     <xsl:template match="Cell">
      <xsl:param name="pText" as="xs:string*"/>
    
      <xsl:apply-templates select="*[1]">
       <xsl:with-param name="pText" select="$pText"/>
      </xsl:apply-templates>
     </xsl:template>
    
     <xsl:template match="Cell/*">
      <xsl:param name="pText" as="xs:string*"/>
    
      <xsl:variable name="vText" as="xs:string*"
       select="$pText, string(.)"/>
    
      <xsl:sequence select=
       "$vText
          [not(current()/../following-sibling::Cell)]"/>
      <xsl:apply-templates select="../following-sibling::Cell[1]">
        <xsl:with-param name="pText" select="$vText"/>
      </xsl:apply-templates>
      <xsl:apply-templates select="following-sibling::*">
        <xsl:with-param name="pText" select="$pText"/>
      </xsl:apply-templates>
     </xsl:template>
    </xsl:stylesheet>
    

    应用于提供的 XML 文档时:

    <Section>
        <Chapter>
            <Cell colname="1">
                <Value>A</Value>
            </Cell>
            <Cell colname="2">
                <MyValue>AAA</MyValue>
                <MyValue>BBB</MyValue>
            </Cell>
            <Cell colname="3">
                <MyCar>Honda</MyCar>
            </Cell>
        </Chapter>
        <Chapter>
            <Cell colname="1">
                <Value>C</Value>
            </Cell>
            <Cell colname="2">
                <MyValue>CCC</MyValue>
            </Cell>
            <Cell colname="3">
                <MyCar>Toyota</MyCar>
            </Cell>
        </Chapter>
    </Section>
    

    准确生成所需的正确结果:

    A AAA Honda A BBB Honda C CCC Toyota
    

    解释:

    1. 这本质上是一项任务,用于生成属于 N 个组的所有值组合(Cell 的子项组成一个组),从每个组中取出一项。

    2. 在组 K 的任何项目中,我们将此项目添加到组 1、2、...、K-1 的当前项目组合中。然后我们将这个新形成的组合传递给组 K+1。如果我们是最后一组 (N) 中的一个项目,我们会打印 (xsl:sequence) 整个累积组合。

    3. 当控件返回时,剩余组 (K+1, K+2, ..., N) 的所有元素组合都已附加到我们当前组 1、2 的组项组合中, ..., K。所有这些组合都已经打印出来了。

    4. 我们将传递给我们的相同组元素组合传递给我们 - 现在我们将它传递给当前组中的以下项目(以下兄弟)。

    【讨论】:

    • Dimitre:谢谢,将您的解决方案与 Lukasz 的解决方案进行比较,它们有很大不同,因为我仍在学习,您介意解释一下您的方法吗?再次感谢!
    • @JohnX:当然,我会在接下来的 10 分钟内编辑我的答案。
    • @infantprogrammer'Aravind':一如既往,我们非常重视您的赞赏。 :)
    • Dimitre:我不清楚这个 [not(current()/../following-sibling::Cell)] 这是什么意思?谢谢!。
    • 另一个问题.. xsl:sequence 实际在哪里使用?.
    【解决方案2】:

    我已经稍微修改了你的方法,因为我猜你真的不想使用&lt;xsl:message&gt; 诊断操作。除此之外,我没有在输出中生成 XML,也没有使用 for-each:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xsl:output method="text" version="1.0" encoding="iso-8859-1"   indent="yes"/>
        <xsl:template match="/Section">
            <xsl:apply-templates select="Chapter"/>
        </xsl:template>
        <xsl:template match="Chapter">
            <xsl:apply-templates select="Cell/MyValue" />
        </xsl:template>
        <xsl:template match="MyValue">
                <xsl:value-of select="../../Cell[@colname='1']/Value/text()"/>
                <xsl:text> </xsl:text>
                <xsl:value-of select="."/>
                <xsl:text> </xsl:text>
                <xsl:value-of select="../../Cell[@colname='3']/MyCar"/>
                <xsl:text> </xsl:text>
        </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

    • 感谢 Lukasz,感谢您的帮助。我想从您的解决方案来看,我必须更频繁地使用应用模板:)。
    • Lukasz,您可能有兴趣看到更通用的解决方案... :)
    猜你喜欢
    • 2020-09-22
    • 1970-01-01
    • 2012-03-16
    • 2016-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-23
    相关资源
    最近更新 更多