从兄弟姐妹到嵌套元素的xslt

时间:2018-09-04 08:52:55

标签: xslt

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

从此xml(注意,我不知道父节点的子节点数):

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

2 个答案:

答案 0 :(得分: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属性包含的值不是有效的元素名称,则转换将失败。

答案 1 :(得分:0)

这里是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>

由于流式处理无法进行同级导航,我认为这是通过流式递归处理同级式的一种方法。