无法使用XSLT在XML中创建嵌套元素

时间:2011-06-08 07:55:47

标签: xslt

我有一个扁平的XML,如下所示:

<objectDataList>
<objectData>
    <equipment>
        <name>Chassis-One</name>
        <type>Chassis</type>
    </equipment>
</objectData>
<objectData>
    <equipment>
        <name>Shelf-One</name>
        <type>Shelf</type>
    </equipment>
</objectData>
<objectData>
    <equipment>
        <name>Shelf-Two</name>
        <type>Shelf</type>
    </equipment>
</objectData>
<objectData>
    <equipment>
        <name>Slot-One</name>
        <type>Slot</type>
    </equipment>
</objectData>

如何创建一个将我的XML转换为另一个XML的XSL:

<equipments>
<object>
    <name>Chassis-One</name>
        <object>
            <name>Shelf-One</name>
            <object>
                <name>Slot-One</name>
            </object>
        </object>

</object>

就像在一个机箱中,有两个架子,而在一个架子里,有一个Slot -One ..

我尝试了一半,但我想不出如何使元素嵌套:

<xsl:template match="/response">
    <equipments>            
            <object>
                <xsl:apply-templates select="objectData"/>
            </object>
    </equipments>

<xsl:template match="objectData/equipment[type='Chassis']">
    <name><xsl:value-of select="equipment/name"/></name>
        <!-- Now I want to find the shelf according to the chassis name -->
        <xsl:call-template name="find-shelf-according-to-chasis-name">
            <xsl:with-param name="chassisName" select="equipment/name"/>
        </xsl:call-template>
</xsl:template>

我希望有人可以解释一下

提前谢谢

2 个答案:

答案 0 :(得分:0)

以下脚本将执行您想要的操作,由于机箱 - 机架 - 插槽结构必须在脚本中表示,因此它有点冗长。如果你的xml包含id和parent-id属性,那么脚本可能会更小,并且可以删除或放宽命名约定。

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

  <xsl:output method="xml"/>

  <xsl:template match="/">
    <equipments>
    <xsl:apply-templates select="//equipment[type='Chassis']" />
    </equipments>
  </xsl:template>

  <xsl:template match="equipment[type='Chassis']">
    <xsl:variable name="suffix" select="substring-after(name, '-')" />
    <object>
        <xsl:copy-of select="name" />
        <xsl:apply-templates select="//equipment[type='Shelf'][substring-after(name, '-')=$suffix]" />
    </object>
  </xsl:template>


  <xsl:template match="equipment[type='Shelf']">
    <xsl:variable name="suffix" select="substring-after(name, '-')" />
    <object>
        <xsl:copy-of select="name"/>
        <xsl:apply-templates select="//equipment[type='Slot'][substring-after(name, '-')=$suffix]" />
    </object>
  </xsl:template>

  <xsl:template match="equipment[type='Slot']">
    <object>
        <xsl:copy-of select="name"/>
    </object>
  </xsl:template>

</xsl:stylesheet>

您要求的部分使用substring-after函数来确定名称后缀,并在后续选择中使用它。

答案 1 :(得分:0)

有一个相当简单(虽然有点冗长)的解决方案:

<xsl:template match="objectDataList">
  <equipments>
    <xsl:apply-templates select="objectData[equipment/type='Chassis']"/>
  </equipments>
</xsl:template>

<xsl:template match="objectData[equipment/type='Chassis']">
  <xsl:variable name="index" select="substring-after(equipment/name,'-')" />
  <object>
    <xsl:copy-of select="equipment/name" />
    <xsl:apply-templates select="following-sibling::objectData[equipment/type='Shelf' and substring-after(equipment/name,'-') = $index]" />
  </object>
</xsl:template>

<xsl:template match="objectData[equipment/type='Shelf']">
  <xsl:variable name="index" select="substring-after(equipment/name,'-')" />
  <object>
    <xsl:copy-of select="equipment/name" />
    <xsl:apply-templates select="following-sibling::objectData[equipment/type='Slot' and substring-after(equipment/name,'-') = $index]" />
  </object>
</xsl:template>

<xsl:template match="objectData[equipment/type='Slot']">
  <xsl:variable name="index" select="substring-after(equipment/name,'-')" />
  <object>
    <xsl:copy-of select="equipment/name" />
  </object>
</xsl:template>

虽然有点重复,但最后三个模板几乎完全相同。但是,根据您的具体要求,它们可能会由不同的模板处理。

如果您可以保证货架始终跟随相关机箱等,那么您可以将第二个模板中的<xsl:apply-templates更改为:

<xsl:apply-templates select="following-sibling::*[1]">

如果可能没有,那么你可以这样做:

<xsl:apply-templates select="following-sibling::*[1][equipment/type='Shelf']">