使用XSLT展平嵌套XML

时间:2016-06-09 15:36:53

标签: xml xslt

我很难编写一个XSLT来将具有相同属性值的所有节点移动到同一级别。

以下是一个例子:

<root>
    <object Name="1">
        <Property Name="a1" Value="a">
            <Property Name="a1.1" Value="a"/>
            <Property Name="a1.2" Value="a">
                <Property Name="a1.2.1" Value="a"/>
                <Property Name="a1.2.2" Value="a"/>
            </Property>
        </Property>
        <Property Name="b1" Value="b"/>
    </object>
</root>

目前,可以将值为a的属性嵌套在另一个内部(节点数量或嵌套级别没有限制)。此模型将更改为仅在对象级别允许此类型的属性。 转换后应该是这样的(元素的顺序无关紧要):

<root>
    <object Name="1">
        <Property Name="a1" Value="a"/>
        <Property Name="a1.1" Value="a"/>
        <Property Name="a1.2" Value="a">
        <Property Name="a1.2.1" Value="a"/>
        <Property Name="a1.2.2" Value="a"/>
        <Property Name="b1" Value="b"/>
    </object>
</root>

我尝试用this very similar question解决这个问题,主要区别在于示例中不会复制节点,但会使用其值。我一直无法弄清楚如何复制整个节点。

修改
上面的例子过于简化了。属性将包含必须复制的子元素

<root>
    <object Name="1">
        <Property Name="a1" Value="a">
            <x>x1</x>
            <y>y1</y>
            <z>z1</z>
            <Property Name="a1.1" Value="a">
                <x>x1.1</x>
                <y>y1.1</y>
                <z>z1.1</z>
            </Property>
            <Property Name="a1.2" Value="a">
                <x>x1.2</x>
                <y>y1.2</y>
                <z>z1.2</z>
                <Property Name="a1.2.1" Value="a">
                    <x>x1.2.1</x>
                    <y>y1.2.1</y>
                    <z>z1.2.1</z>
                </Property>
                <Property Name="a1.2.2" Value="a">
                    <x>x1.2.1</x>
                    <y>y1.2.1</y>
                    <z>z1.2.1</z>
                </Property>
            </Property>
        </Property>
        <Property Name="b1" Value="b"/>
    </object>
</root>

转型后应该成为这个:

<root>
    <object Name="1">
        <Property Name="a1" Value="a">
            <x>x1</x>
            <y>y1</y>
            <z>z1</z>
        </Property>
        <Property Name="a1.1" Value="a">
            <x>x1.1</x>
            <y>y1.1</y>
            <z>z1.1</z>
        </Property>
        <Property Name="a1.2" Value="a">
            <x>x1.2</x>
            <y>y1.2</y>
            <z>z1.2</z>
        </Property>
        <Property Name="a1.2.1" Value="a">
            <x>x1.2.1</x>
            <y>y1.2.1</y>
            <z>z1.2.1</z>
        </Property>
        <Property Name="a1.2.2" Value="a">
            <x>x1.2.1</x>
            <y>y1.2.1</y>
            <z>z1.2.1</z>
        </Property>
        <Property Name="b1" Value="b"/>
    </object>
</root>

2 个答案:

答案 0 :(得分:2)

如果你从XSLT identity template开始,你需要的只是另一个匹配Property的模板,它复制元素和属性,但输出元素之后的子元素,而不是元素。

<xsl:template match="Property">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
  </xsl:copy>
  <xsl:apply-templates select="node()" />
</xsl:template>

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Property">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
    </xsl:copy>
    <xsl:apply-templates select="node()" />
  </xsl:template>
</xsl:stylesheet>

请注意,我假设Property个元素在此处只能包含其他Property个元素。

答案 1 :(得分:1)

重新编辑您的问题 - 请尝试以下方式:

XSLT 1.0

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

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

<xsl:template match="Property">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()[not(self::Property)]"/>
    </xsl:copy>
    <xsl:apply-templates select="Property" />
</xsl:template>

</xsl:stylesheet>