【问题标题】:Limits of XSLT Grouping?XSLT 分组的限制?
【发布时间】:2015-03-01 05:10:57
【问题描述】:

我需要通过将相关元素分组到新的组元素下,将下面的 sn-p 更改为层次结构。 XSLT 听起来像是在这里使用的合适技术,但我对它的了解还不够,无法评估它是否能够满足我的需求。一个示例分组标准是“1个'd'节点后跟一些'3'节点,然后是1个'f'节点”。我必须针对几个单独的条件执行此任务,所以我想知道在 XSLT 中是否可以进行这种性质的查询,或者我是否会更好地放弃并以程序方式处理 DOM。我也对其他策略完全开放。对于一个具体的例子,我需要转换这个-

<root>
    <a>foo</a>
    <b>bar</b>
    <c>baz</c>
    <d>location</d>
    <e>3.14</e>
    <e>6.02</e>
    <e>1.23</e>
    <f>2015</f>
    <d>location</d>
    <e>3.14</e>
    <e>6.02</e>
    <f>2015</f>
</root>

进入这个-

<root>
    <a>foo</a>
    <b>bar</b>
    <c>baz</c>
    <sample>
        <d>location</d>
        <e>3.14</e>
        <e>6.02</e>
        <e>1.23</e>
        <f>2015</f>
    </sample>
    <sample>
        <d>location</d>
        <e>3.14</e>
        <e>6.02</e>
        <f>2015</f>
    </sample>
</root> 

【问题讨论】:

  • 输入 XML 在d 之后是否可以有超过 3 个(或更少,或没有)e 元素? f 元素的相同问题,是否有更多或没有。你想怎么处理?请提及您正在使用的 XSLT 版本? 1.0 还是 2.0?
  • 任何分组问题的解决方案都将取决于您使用的是 1.0 还是 2.0。你需要说。

标签: xml xslt xslt-grouping


【解决方案1】:

如果你想对元素进行分组,以d开头,你可以使用下面的方法。 XSLT-1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" method="xml" />
    <xsl:strip-space elements="*"/>

    <!-- key to select following (e|f) elements using the first preceding d's id -->
    <xsl:key name="following" match="e | f" use="generate-id(preceding::d[1])"/>

    <!-- identity transform template -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- template to group d and its following (e|f) elements under sample element-->
    <xsl:template match="d">
        <sample>
            <xsl:copy-of select="current() | key('following', generate-id())"/>
        </sample>
    </xsl:template>

    <!-- template to do nothing for e|f elements -->
    <xsl:template match="e|f"/>

</xsl:stylesheet>

当然,XSLT 不仅限于这种简单的分组。

【讨论】:

  • 完美!作为后续问题 - 如果我需要在更高级别对组进行“分组”,我可以稍后在样式表中添加其他模板,还是完全不需要在另一个样式表中完成?
  • @JSacksteder 我很高兴代码对你有用。这取决于所需的转换。在更高级别上,分组也可以在单个样式表中完成。无论是在一个转变阶段还是在多个阶段。通过多个阶段,我的意思是,有一个变量来存储当前的转换,并再次使用 exslt:node-set() 在该变量上运行更多模板。如果您使用 XSLT-2.0,它会变得更加容易。您可以编辑当前问题或提出新问题。
  • 这假定“e”元素紧跟“d”元素。如果这个假设不成立,将会产生不正确的结果。
  • @DimitreNovaatchev 我认为 OP 在此语句中犯了一个错误后跟一些“3”节点,实际上是指e 节点。
  • @JSacksteder 如果我的假设正确,请您更新您的问题。
【解决方案2】:

鉴于我通常在 XSLT 1.0 环境中工作,这是我对一种方法的看法。

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:output method="xml"/>

    <!-- any nodes that I don't address specifically, I copy -->
    <xsl:template match="*">
        <xsl:copy-of select="."/>
    </xsl:template>

    <!-- from the root, deal with a, b, c, d nodes -->
    <xsl:template match="root">
        <root>
            <xsl:apply-templates select="a|b|c|d"/>
        </root>
    </xsl:template>

    <!-- the d node is the fun one -->
    <xsl:template match="d">
        <!-- add the wrapper -->
        <sample>
            <!-- first, copy the d node -->
            <xsl:copy-of select="."/>
            <!--
            process any following sibling e nodes if that
            e node's immediately preceding d sibling is the
            "current" node - i.e. the d node that got us here

            We use the fact that in XSLT 1.0, a union of nodes
            will never contain duplicates, so if the count is
            one, that means the two parts of the union are the
            same node
            -->
            <xsl:apply-templates select="following-sibling::e
                [count(current() | preceding-sibling::d[1]) = 1]"/>
            <!-- same logic for f nodes -->
            <xsl:apply-templates select="following-sibling::f
                [count(current() | preceding-sibling::d[1]) = 1]"/>
        </sample>
    </xsl:template>
</xsl:stylesheet>

现在,我想这是否让您相信 XSLT 是正确的工具或让您惊恐地尖叫取决于您的个性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    相关资源
    最近更新 更多