使用 XSLT/XPath 2.0 以某种方式输出值

发布于 2025-01-08 21:10:10 字数 2004 浏览 0 评论 0原文

我有一个像这样的 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 本田 一个 血脑屏障 本田 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 会更改上下文,因此剩余的值不会执行任何操作。

解决方案是什么 ?

这个

为了

I have an XML like this:

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

I like the have a message (later on convert them tags) output like this:

A
AAA
Honda
A
BBB
Honda
C
CCC
Toyota

This is my 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>

Unfortunately it doesn't output what I'd like it to do :(.

I realize that for-each will change the context so the remaining value-ofs won't do anything.

What would be a solution for this ?.

TIA,

John

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北笙凉宸 2025-01-15 21:10:10

此 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. 我们传递与传递给我们的相同的组元素组合 - 现在我们将其传递给当前组中的下一个项目(后续同级)。

This XSLT 2.0 transformation (the equivalent XSLT 1.0 transformation can be mechanically written from this one).

Do note: This is a generic solution that works with any number of children and doesn't rely on hardcoded names.

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

when applied on the provided XML document:

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

produces exactly the wanted, correct result:

A AAA Honda A BBB Honda C CCC Toyota

Explanation:

  1. This is essentially a task for producing all combinations of values that belong to N groups (the children of a Cell make a group), taking one item from each group.

  2. At any item of group K, we add this item to the current combination of items of the groups 1, 2, ..., K-1. Then we pass this newly formed combination to the group K+1. If we are an item in the last group (N), we print out (xsl:sequence) the whole accumulated combination.

  3. When the control returns, all combinations of elements of the remaining groups (K+1, K+2, ..., N) have been appended to our current combination of the group items of groups 1, 2, ..., K. All these combinations have already been printed.

  4. We pass the same group elements combination that was passed to us -- now we pass it to the following item in the current group (the following-sibling).

送君千里 2025-01-15 21:10:10

我对您的方法进行了一些修改,因为我猜测您确实不想使用 诊断操作。除此之外,我没有在输出上生成 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>

I have modified your approach a little, because I'm guessing that you really don't want to use <xsl:message> diagnostic operation. Besides that, I'm not generating XML on the output and I'm not using 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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文