【问题标题】:xslt from siblings to nested elementsxslt 从兄弟元素到嵌套元素
【发布时间】:2018-09-04 08:52:55
【问题描述】:

我是一个 xslt 初学者,我真的在努力完成以下任务:

来自这个xml(NB我不知道父节点的子节点数量):

<parent>
  <element_a id="e1"/>
  <element_b id="e2"/>
  <element_a id="e3"/>
  <element_c id="e4"/>
  ...
</parent>

我需要得到这个xml:

<e1>
  <e2>
    <e3>
      <e4>
        ...
      </e4>
    </e3>
  </e2>
</e1>

我已经尝试了几次,但我无法获得正确的输出。这是一种尝试:

<xsl:template name="test">
    <xsl:element name="{@id}">
        <xsl:if test="position() != last()">
            <xsl:call-template name="test"/>
        </xsl:if>
    </xsl:element>
</xsl:template>
<xsl:template match="parent">
    <parent>
        <xsl:for-each select="./*">
            <xsl:for-each select=".">
                <xsl:element name="{@id}">
                    <xsl:if test="position() != last()">
                        <xsl:call-template name="test"/>
                    </xsl:if>
                </xsl:element>
            </xsl:for-each>
        </xsl:for-each>
    </parent>
</xsl:template>

【问题讨论】:

  • 即使不正确,您能否在问题中包含您尝试过的 XSLT?实际上,您可能离解决方案并不遥远。谢谢!
  • 您尝试的一个问题是您命名模板中的&lt;xsl:call-template name="test"/&gt; 指令实际上并没有改变当前元素,因此它会在同一个元素上无限递归。

标签: xslt


【解决方案1】:

这是一种方法:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="parent">
      <xsl:apply-templates select="*[1]"/>
    </xsl:template>

    <xsl:template match="parent/*">
      <xsl:element name="{@id}">
        <xsl:apply-templates select="following-sibling::*[1]"/>
      </xsl:element>
    </xsl:template>
</xsl:stylesheet>

显然,您需要添加一些对其他元素的特定处理,但希望这可以为您指明正确结构的方向。

它的工作原理是让父元素只处理它的第一个子元素,然后让父元素的每个子元素创建一个名称与id 属性匹配的元素,然后递归地将下一个元素作为新子元素处理。

一个问题 - 如果 id 属性曾经包含一个不是有效元素名称的值,则转换将失败。

【讨论】:

  • 非常感谢!我现在明白了。
  • 作为参考,这种技术有时被称为“兄弟递归”:这个想法是元素的模板规则将模板应用于紧随其后的兄弟,其匹配的模板规则然后做同样的事情,递归。
【解决方案2】:

这是 XSLT 3 中的一个替代方案,它在递归函数中使用 for-each-group 来尝试以允许使用 Saxon 9.8 EE 等处理器或 Saxon 9.8 或其他版本中的普通 XSLT 3 处理的流式处理的方式实现嵌套Altova(不支持流式传输):

<?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"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="#all"
    version="3.0">

    <xsl:mode on-no-match="shallow-copy" streamable="yes"/>

    <xsl:output method="xml" indent="yes"/>

    <xsl:function name="mf:nest" as="node()*" streamability="absorbing">
        <xsl:param name="nodes" as="node()*"/>
        <xsl:for-each-group select="$nodes" group-adjacent="true()">
            <xsl:element name="{@id}">
                <xsl:sequence select="mf:nest(tail(current-group()))"/>
            </xsl:element>
        </xsl:for-each-group>
    </xsl:function>

    <xsl:template match="parent">
        <xsl:copy>
            <xsl:sequence select="mf:nest(*)"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

由于流式传输无法实现同级导航,我认为这是使用流式递归处理同级的一种方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-15
    • 2018-02-17
    • 1970-01-01
    • 2021-12-28
    • 1970-01-01
    相关资源
    最近更新 更多