2

我有一个这样的 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>

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

A AAA 本田 A 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,

约翰

4

2 回答 2

3

这个 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. 我们将传递给我们的相同组元素组合传递给我们——现在我们将它传递给当前组中的以下项目(以下兄弟)。

于 2012-02-26T00:04:28.743 回答
1

我对您的方法进行了一些修改,因为我猜您确实不想使用<xsl:message>诊断操作。除此之外,我没有在输出中生成 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>
于 2012-02-25T23:40:50.213 回答