将嵌套的XML元素转换为相等的父元素;删除父级

时间:2013-09-19 12:34:06

标签: xml xslt

我有一段XML,如下所示:

<LISTOFHARDWARE>
    <HARDWARE>
        <item>
            <SERIALNUMBER>D4242050101</SERIALNUMBER>
            <STATUS>2 </STATUS>
            <STATUSREASON>998 </STATUSREASON>
            <MACADDRESS />
            <LINKEDSMARTCARD>4135237101</LINKEDSMARTCARD>
            <PRODUCTDETAIL>
                <TYPE>DEVICE</TYPE>
                <MODEL>ABC123</MODEL>
            </PRODUCTDETAIL>
        </item>
        <item>
            <SERIALNUMBER>D4242050101</SERIALNUMBER>
            <STATUS>2 </STATUS>
            <STATUSREASON>998 </STATUSREASON>
            <MACADDRESS />
            <LINKEDSMARTCARD>4135237101</LINKEDSMARTCARD>
            <PRODUCTDETAIL>
                <TYPE>DEVICE</TYPE>
                <MODEL>ABC123</MODEL>
            </PRODUCTDETAIL>
        </item>
    </HARDWARE>
</LISTOFHARDWARE>   

我希望<item>元素替换为<HARDWARE>元素(直接父元素),以及要删除的父<HARDWARE>元素,以便结果如下所示:

<LISTOFHARDWARE>
    <HARDWARE>
        <SERIALNUMBER>D4242050101</SERIALNUMBER>
        <STATUS>2 </STATUS>
        <STATUSREASON>998 </STATUSREASON>
        <MACADDRESS />
        <LINKEDSMARTCARD>4135237101</LINKEDSMARTCARD>
        <PRODUCTDETAIL>
            <TYPE>DEVICE</TYPE>
            <MODEL>ABC123</MODEL>
        </PRODUCTDETAIL>
    </HARDWARE>
    <HARDWARE>
        <SERIALNUMBER>D4242050101</SERIALNUMBER>
        <STATUS>2 </STATUS>
        <STATUSREASON>998 </STATUSREASON>
        <MACADDRESS />
        <LINKEDSMARTCARD>4135237101</LINKEDSMARTCARD>
        <PRODUCTDETAIL>
            <TYPE>DEVICE</TYPE>
            <MODEL>ABC123</MODEL>
        </PRODUCTDETAIL>

    </HARDWARE>
</LISTOFHARDWARE>   

我是否可以在XSL转换中执行此操作,该转换适用于包含<item>个元素的任何XML文件?

修改

在得到这个答案的帮助和进一步的研究后,我几乎就在那里,但并不完全。请考虑以下事项:

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

    <!--  Replace <item> with name of parent element -->
    <xsl:template match="item">
        <xsl:element name="{name(..)}">
            <xsl:apply-templates select="@*|node()" />
        </xsl:element>
    </xsl:template>

    <!-- Remove immediate parent of <item> elements -->
    <xsl:template match="item/.."> <!-- Results in syntax error --> 
            <xsl:apply-templates select="@*|node()" />
    </xsl:template>

</xsl:stylesheet>

问题是,在成功将<item>元素更改为父级名称后,我无法通过动态引用其父级来删除任何item元素的父级。

3 个答案:

答案 0 :(得分:3)

这是一种方法:

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

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

  <!-- Process any element that has "item" as child -->
  <xsl:template match="*[item]">
    <xsl:apply-templates/>
  </xsl:template>

  <!-- Replace "item" with its parent in source XML -->
  <xsl:template match="item">
    <xsl:element name="{name(..)}">
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

首先需要了解可用于复制XML中不需要任何更改的所有节点的Identity Transform

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

您需要简化您认为转换的工作方式,因为您所说的只是删除元素,但保留其子项。要做到这一点,只需另一个简单模板后缀

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

所有这一切都与 item 元素相匹配,但只是继续处理其子元素而不复制 item 元素本身(并且子节点只是被复制了身份模板)。

试试这个XSLT

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

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

答案 2 :(得分:1)

这个怎么样?

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

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

    <xsl:template match="/*">
        <xsl:element name="{node-name(.)}">
            <xsl:for-each select="*/item">
                <xsl:element name="{node-name(..)}">
                  <xsl:copy-of select="./*" />
                </xsl:element>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

编辑OP:对于我的情况,我必须将函数node-name()更改为name(),否则无法编译。