如何使用for-each在xslt中按id对元素进行分组

时间:2016-01-26 15:23:27

标签: xml xslt xpath

我是XSLT和XPATH的新手,我有以下xml文件:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Levels>
  <Level id="1">com</Level>
  <Level id="2">bitstew</Level>
  <Level id="3">data</Level>
  <Level id="4">activity_plan</Level>
  <File id="activity_plan">ActivityPlanToDailyPlan.xml</File>
  <Level id="1">com</Level>
  <Level id="2">bitstew</Level>
  <Level id="3">director-services</Level>
  <Level id="4">manage</Level>
  <Level id="5">adapters</Level>
  <File id="adapters">Adapters.xml</File>
  <Level id="1">com</Level>
  <Level id="2">bitstew</Level>
  <Level id="3">director-services</Level>
  <Level id="4">manage</Level>
  <Level id="5">adapters</Level>
  <File id="adapters">Adapters_DELETE.xml</File>
  <Level id="1">com</Level>
  <Level id="2">bitstew</Level>
  <Level id="3">director-services</Level>
  <Level id="4">manage</Level>
  <Level id="5">adapters</Level>
  <File id="adapters">Adapters_GET.xml</File>
  <Level id="1">com</Level>
  <Level id="2">bitstew</Level>
  <Level id="3">director-services</Level>
  <Level id="4">manage</Level>
  <Level id="5">adapters</Level>
  <File id="adapters">Adapters_POST.xml</File>
  <Level id="1">com</Level>
  <Level id="2">bitstew</Level>
  <Level id="3">director-services</Level>
  <Level id="4">manage</Level>
  <Level id="5">adapters</Level>
  <File id="adapters">Adapters_PUT.xml</File>
  <Level id="1">com</Level>
  <Level id="2">griddirector</Level>
  <Level id="3">director</Level>
  <Level id="4">services</Level>
  <Level id="5">advanced_search_results</Level>
  <File id="advanced_search_results">advanced_search_results.xml</File>
  <Level id="1">com</Level>
  <Level id="2">bitstew</Level>
  <Level id="3">adk</Level>
  <Level id="4">lib</Level>
  <Level id="5">general_aggregations</Level>
  <File id="general_aggregations">aggnode.xml</File>
</Levels>

我想用ids对元素进行分组,使用xslt for-each,我可以使用它作为树状结构(左侧菜单)。

所需输出为:

<com>
    <bitstew>
        <data>
            <activity_plan>
                <file>ActivityPlanToDailyPlan.xml<file>
            </activity_plan>
        </data>
        <director-services>
            <manage>
                <adapters>
                    <file>Adapters.xml</file>
                    <file>Adapters_DELETE.xml</file>
                    <file>Adapters_GET.xml</file>
                    <file>Adapters_POST.xml</file>
                    <file>Adapters_PUT.xml</file>
                </adapters>
            </manage>
        </director-services>
        <adk>
            <lib>
                <general_aggregations>
                    <file>aggnode.xml</file>
                </general_aggregations>
            </lib>
        </adk>
    </bitstew>
    <griddirector>
        <director>
            <services>
                <advanced_search_results>
                    <file>advanced_search_results.xml</file>
                </advanced_search_results>
            </services>
        </director>
    </griddirector>
</com>

我无法使用<xsl:apply-template><xsl:template><xsl:for-each-group>语句。我不知道如何使用<xsl:for-each>构建。

任何帮助都将受到高度赞赏......谢谢!

1 个答案:

答案 0 :(得分:0)

您可以通过正确使用<xsl:variable />来解决您的任务。

我已经完成了简单的XSLT文件(您可以只为您的处理器调整逻辑):

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

    <xsl:output indent="yes"/>

    <!-- This is just dinamicaly calculated unique sequence of available ids.
    These ids could be just hard-coded if it is suitable for you. -->
    <xsl:key name="level" match="//Level/@id" use="."/>
    <xsl:variable name="levelIds">
        <xsl:for-each select="//Level/@id[generate-id() = generate-id(key('level', .)[1])]">
            <xsl:element name="id">
                <xsl:value-of select="."/>
            </xsl:element>
        </xsl:for-each>
    </xsl:variable>

    <xsl:template match="/">
        <!-- List of all Level-s -->
        <xsl:variable name="all-levels" select="//Level"/>

        <!-- Creating result variable with grouped content -->
        <xsl:variable name="grouped-values">

            <!-- Iterating over unique level ids -->
            <xsl:for-each select="$levelIds/id">

                <!-- Creating element for every level -->
                <xsl:variable name="level-id" select="."/>
                <xsl:element name="level">
                    <xsl:attribute name="id">
                        <xsl:value-of select="$level-id"/>
                    </xsl:attribute>

                    <!-- Extracting and listing appropriate to this level values -->
                    <xsl:for-each select="$all-levels[@id = $level-id]">
                        <xsl:element name="value">
                            <xsl:value-of select="text()"/>
                        </xsl:element>
                    </xsl:for-each>
                </xsl:element>
            </xsl:for-each>
        </xsl:variable>

        <!-- Just testing output for correctness -->
        <xsl:element name="grouped-values">
            <xsl:copy-of select="$grouped-values/level"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

正如您在此处看到的那样是分组输出:

<?xml version="1.0" encoding="utf-8"?>
<grouped-values>
   <level id="1">
      <value>com</value>
      <value>com</value>
      <value>com</value>
      <value>com</value>
      <value>com</value>
      <value>com</value>
      <value>com</value>
      <value>com</value>
   </level>
   <level id="2">
      <value>bitstew</value>
      <value>bitstew</value>
      <value>bitstew</value>
      <value>bitstew</value>
      <value>bitstew</value>
      <value>bitstew</value>
      <value>griddirector</value>
      <value>bitstew</value>
   </level>
   <level id="3">
      <value>data</value>
      <value>director-services</value>
      <value>director-services</value>
      <value>director-services</value>
      <value>director-services</value>
      <value>director-services</value>
      <value>director</value>
      <value>adk</value>
   </level>
   <level id="4">
      <value>activity_plan</value>
      <value>manage</value>
      <value>manage</value>
      <value>manage</value>
      <value>manage</value>
      <value>manage</value>
      <value>services</value>
      <value>lib</value>
   </level>
   <level id="5">
      <value>adapters</value>
      <value>adapters</value>
      <value>adapters</value>
      <value>adapters</value>
      <value>adapters</value>
      <value>advanced_search_results</value>
      <value>general_aggregations</value>
   </level>
</grouped-values>

现在您可以使用简单的两个嵌套$grouped-values项来处理这些<xsl:for-each>,具体取决于您的需求,例如:

<xsl:for-each select="$grouped-values/level">
    <xsl:variable name="level" select="."/>

    <xsl:for-each select="$level/value">

        <xsl:element name="value">
            <xsl:attribute name="id">
                <xsl:value-of select="$level/@id"/>
            </xsl:attribute>
            <xsl:value-of select="text()"/>
        </xsl:element>

    </xsl:for-each>
</xsl:for-each>
祝你好运!