XSLT 1.0从父子关系构建层次结构

时间:2016-01-16 16:05:45

标签: xml xslt

我有以下平面xml结构。

<customUI >
  <elements>
    <tab id="1" parent="0"/>
    <tab id="-1" parent="0"/>
    <group id="-2"  parent="-1"/>
    <group id="2"  parent="1"/>
    <group id="11"  parent="1"/>
    <menu id="-27"  parent="-26"/>
    <menu id="-24" parent="-4"/>
    <menu id="-18" parent="-4"/>
    <menu id="-11"  parent="-9"/>
    <menu id="-10" parent="-9"/>
    <menu id="-3"  parent="-2"/>
    <menu id="3"  parent="2"/>
    <menu id="10" parent="65"/>
    <menu id="12"  parent="11"/>
    <menu id="16"  parent="11"/>
    <menu id="18" parent="11"/>
    <menu id="25" parent="11" />
    <menu id="29" parent="11"/>
    <menu id="46" parent="11"/>
    <menu id="74" parent="-3"/>
    <menu id="85" parent="11"/>
    <menu id="89" parent="2"/>
    <menu id="95" parent="2"/>
    <menu id="104"  parent="2"/>
    <button id="-28"  parent="-2"/>
    <button id="-25" parent="-24"/>
    <button id="-12" parent="-11"/>
    <button id="32" parent="29"/>
    <button id="26" parent="25"/>
    <button id="41" parent="18"/>
    <button id="66" parent="46"/>
    <button id="82"  parent="74"/>
    <button id="86" parent="46"/>
    <button id="87"  parent="89"/>
    <button id="90"  parent="89"/>
    <button id="99"  parent="89"/>
    <button id="58"  parent="16"/>
    <button id="42" parent="18"/>
    <button id="47"  parent="46"/>
    <button id="48"  parent="46"/>
    <button id="33" parent="29"/>
    <!-- The list continues -->
  </elements>
</customUI>

我想要做的是使用'id'值和'parent'值之间的关系来构建层次结构。

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

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

<xsl:template match="tab">
    <xsl:variable name="controllerId" select="@id" as="xs:string"/>
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <xsl:copy-of select="//*[@parent = $controllerId]"/>
    </xsl:copy>
</xsl:template>


<xsl:template match="group" name="group">
    <xsl:variable name="controllerId" select="@id" as="xs:string"/>
    <xsl:copy>
       <xsl:apply-templates select="@*|node()"/>
       <xsl:copy-of select="//*[@parent = $controllerId]"/>
    </xsl:copy>
</xsl:template>


<xsl:template match="menu" name="menu">
    <xsl:variable name="controllerId" select="@id" as="xs:string"/>
    <xsl:copy>
       <xsl:apply-templates select="@*|node()"/>
       <xsl:copy-of select="//*[@parent = $controllerId]"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

这是我到目前为止所尝试过的,但它不起作用。

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

这有点粗糙,但应该有效:

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

  <xsl:template match="elements">
    <xsl:copy>
      <xsl:for-each select="*">
        <xsl:if test="not(../*[@id=current()/@parent])">
          <xsl:apply-templates select="."/>
        </xsl:if>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="elements/*">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      <xsl:apply-templates select="../*[@parent = current()/@id]"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

elements模板会复制它,但对于其中的每个元素,如果没有其他兄弟的父母就是这个,那么它只应用模板;即如果您的数据代表完整的层次结构,它可能只是根。

第二个模板适用于元素模板中的任何内容,并按原样复制,然后还包括递归的父元素是当前元素的任何其他元素。

使用可能更快的键的替代方法,但如果有多个elements元素则会出现问题:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:key name="elemsById" match="elements/*" use="@id"/>
  <xsl:key name="elemsByParent" match="elements/*" use="@parent"/>

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

  <xsl:template match="elements">
    <xsl:copy>
      <xsl:apply-templates select="*[not(key('elemsById',@parent))]"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="elements/*">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      <xsl:apply-templates select="key('elemsByParent',@id)"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>