我需要扁平化一个分层XML结构。现在,这听起来像是一个久经考验的话题,我已经倾注了很多很多的链接。但它们大多是关于从平面结构中创建层次结构的建议。
输入XML -
<bom>
<part>
<name>a</name>
<othernodes>abc</othernodes>
<part>
<name>b</name>
<othernodes>abc</othernodes>
<part>
<name>e</name>
<othernodes>abc</othernodes>
</part>
<part>
<name>f</name>
<othernodes>abc</othernodes>
</part>
</part>
<part>
<name>c</name>
<othernodes>abc</othernodes>
<part>
<name>g</name>
<othernodes>abc</othernodes>
</part>
</part>
<part>
<name>d</name>
<othernodes>abc</othernodes>
</part>
</part>
</bom>
搜索输出-
<bom>
<part>
<parent/>
<name>a</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>a</parent>
<name>b</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>a</parent>
<name>c</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>a</parent>
<name>d</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>b</parent>
<name>e</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>b</parent>
<name>f</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>c</parent>
<name>g</name>
<othernodes>abc</othernodes>
</part>
</bom>
起初我认为这可能是不可能的。然后我试着想出一些xslt。我知道这里的递归是关键,但不确定如何实现。下面是我目前使用的XSLT(显然它不能产生期望的结果)。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes" method="xml" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="bom">
<xsl:element name="bom">
<xsl:apply-templates select="@* | node() [not(child::part)]"/>
<xsl:apply-templates select="part"/>
<!--<xsl:apply-templates select="part/child::part"/>-->
</xsl:element>
</xsl:template>
<xsl:template match="part" >
<xsl:element name="part">
<xsl:element name="parent">
<xsl:value-of select="../part/name"/>
</xsl:element>
<xsl:apply-templates select="@* | node() [not(part)]" />
<xsl:apply-templates select="child::part"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
如果有人能就如何处理和解决这个问题提供一些指导,我将不胜感激。谢谢! 差不多完成了,样式表只需要一些固定装置(这里不需要递归):
- 指令
<xsl:apply-templates select="@* | node() [not(child::part)]"/>
应该使用self::
轴,以正常工作。 -
template match="part"
中的指令必须在<xsl:element>
之外 - 父名称未被正确检索-使用
<xsl:value-of select="../name"/>
代替<xsl:value-of select="../part/name"/>
- 在结果树中输出任何内容之前,请考虑处理属性。
这是你的样式表的更正版本:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes" method="xml" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="bom">
<xsl:element name="bom">
<xsl:apply-templates select="@* | node()"/>
<!--<xsl:apply-templates select="part/child::part"/>-->
</xsl:element>
</xsl:template>
<xsl:template match="part" >
<xsl:element name="part">
<xsl:apply-templates select="@*"/>
<xsl:element name="parent">
<xsl:value-of select="../name"/>
</xsl:element>
<xsl:apply-templates select="node() [not(self::part)]" />
</xsl:element>
<xsl:apply-templates select="child::part"/>
</xsl:template>
</xsl:stylesheet>
这是我得到的结果,与你提供的主要区别在于元素的排序方式不完全相同:
<?xml version="1.0" encoding="UTF-8"?>
<bom>
<part>
<parent/>
<name>a</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>a</parent>
<name>b</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>b</parent>
<name>e</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>b</parent>
<name>f</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>a</parent>
<name>c</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>c</parent>
<name>g</name>
<othernodes>abc</othernodes>
</part>
<part>
<parent>a</parent>
<name>d</name>
<othernodes>abc</othernodes>
</part>
</bom>