Xml 使用XSLT将路径列表转换为树结构

Xml 使用XSLT将路径列表转换为树结构,xml,xslt,tree,xslt-1.0,Xml,Xslt,Tree,Xslt 1.0,我有一个路径列表,我需要把它做成一个树结构。此外,我需要添加一些特定的信息相关的每一个级别 示例输入 <root> <data>2013</data> <data>2013/1</data> <data>2013/1/0</data> <data>2013/1/1</data> <data>2013/1/2</data> <data&g

我有一个路径列表,我需要把它做成一个树结构。此外,我需要添加一些特定的信息相关的每一个级别

示例输入

<root>
  <data>2013</data>
  <data>2013/1</data>
  <data>2013/1/0</data>
  <data>2013/1/1</data>
  <data>2013/1/2</data>
  <data>2013/2</data>
  <data>2013/2/0</data>
  <data>2013/2/1</data>
  <data>2013/2/2</data>
  <data>2013/2/3</data>
</root>

2013
2013/1
2013/1/0
2013/1/1
2013/1/2
2013/2
2013/2/0
2013/2/1
2013/2/2
2013/2/3
我需要让它看起来像这样,例如:

<root>
  <year value="2013">
    <info />
    <month value="1">
      <info />
      <day value="0">
        <info />
      </day>
      <day value="1">
        <info />
      </day>
      ...
    </month>
    ...
  </year>
  ...
</root>

...
...
...
其中信息元素是我从其他地方获得的关于每条路径的信息


我想我可能需要分组或其他什么,但以前从未使用过,通常只是停留在这里。我不知道如何攻击它。非常感谢您的帮助。

以下是使用XSLT2.0的样式表:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/">
    <root>
        <xsl:for-each-group select="root/data" group-by="tokenize(.,'/')[1]">
            <year value="{current-grouping-key()}">
                <info/>
                <xsl:for-each-group select="current-group()" group-by="tokenize(.,'/')[2]">
                    <month value="{current-grouping-key()}">
                        <info/>
                        <xsl:for-each-group select="current-group()" group-by="tokenize(.,'/')[3]">
                            <day value="{current-grouping-key()}">
                                <info/>
                            </day>
                        </xsl:for-each-group>
                    </month>
                </xsl:for-each-group>
            </year>
        </xsl:for-each-group>
    </root>
</xsl:template>
</xsl:stylesheet>

以下是使用XSLT2.0的样式表:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/">
    <root>
        <xsl:for-each-group select="root/data" group-by="tokenize(.,'/')[1]">
            <year value="{current-grouping-key()}">
                <info/>
                <xsl:for-each-group select="current-group()" group-by="tokenize(.,'/')[2]">
                    <month value="{current-grouping-key()}">
                        <info/>
                        <xsl:for-each-group select="current-group()" group-by="tokenize(.,'/')[3]">
                            <day value="{current-grouping-key()}">
                                <info/>
                            </day>
                        </xsl:for-each-group>
                    </month>
                </xsl:for-each-group>
            </year>
        </xsl:for-each-group>
    </root>
</xsl:template>
</xsl:stylesheet>

以下是使用XSLT2.0的样式表:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/">
    <root>
        <xsl:for-each-group select="root/data" group-by="tokenize(.,'/')[1]">
            <year value="{current-grouping-key()}">
                <info/>
                <xsl:for-each-group select="current-group()" group-by="tokenize(.,'/')[2]">
                    <month value="{current-grouping-key()}">
                        <info/>
                        <xsl:for-each-group select="current-group()" group-by="tokenize(.,'/')[3]">
                            <day value="{current-grouping-key()}">
                                <info/>
                            </day>
                        </xsl:for-each-group>
                    </month>
                </xsl:for-each-group>
            </year>
        </xsl:for-each-group>
    </root>
</xsl:template>
</xsl:stylesheet>

以下是使用XSLT2.0的样式表:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/">
    <root>
        <xsl:for-each-group select="root/data" group-by="tokenize(.,'/')[1]">
            <year value="{current-grouping-key()}">
                <info/>
                <xsl:for-each-group select="current-group()" group-by="tokenize(.,'/')[2]">
                    <month value="{current-grouping-key()}">
                        <info/>
                        <xsl:for-each-group select="current-group()" group-by="tokenize(.,'/')[3]">
                            <day value="{current-grouping-key()}">
                                <info/>
                            </day>
                        </xsl:for-each-group>
                    </month>
                </xsl:for-each-group>
            </year>
        </xsl:for-each-group>
    </root>
</xsl:template>
</xsl:stylesheet>

我假设层次结构正好是给定的三个层次。如果每个级别都需要一个具有自己名称的元素,那么就很难实现其他功能。同样出于这个原因,每个级别都必须有一个单独的模板,即使代码在很大程度上是相似的。否则,我们需要某种查找目录来查找“月”之后的内容,例如

(编辑)
还假设每个数据元素(一年除外)都有一个“父”数据元素;i、 e.在转换过程中不必创建中间元素

XSLT1.0

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

<xsl:template match="/root">
    <xsl:copy>
        <xsl:apply-templates 
            select="data[not(contains(., '/'))]" 
            mode="year"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="data" mode="year">
    <year value="{.}">
    <xsl:variable name="dir" select="concat(., '/')" />
        <xsl:apply-templates 
            select="/root/data
                [starts-with(., $dir)]
                [not (contains(substring-after(., $dir), '/'))]"
            mode="month"/>
    </year>
</xsl:template>

<xsl:template match="data" mode="month">
    <month value="{substring-after(., '/')}">
    <xsl:variable name="dir" select="concat(., '/')" />
        <xsl:apply-templates 
            select="/root/data
                [starts-with(., $dir)]
                [not (contains(substring-after(., $dir), '/'))]"
            mode="day"/>
    </month>
</xsl:template>

<xsl:template match="data" mode="day">
    <day value="{substring-after(substring-after(., '/'), '/')}">
    </day>
</xsl:template>

</xsl:stylesheet> 

应用于输入时,结果为:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <year value="2013">
      <month value="1">
         <day value="0"/>
         <day value="1"/>
         <day value="2"/>
      </month>
      <month value="2">
         <day value="0"/>
         <day value="1"/>
         <day value="2"/>
         <day value="3"/>
      </month>
   </year>
</root>


其中信息元素是我从中获得的关于每条路径的信息 在别的地方


我遗漏了这一部分,因为我根本不清楚这将如何工作。我希望您在开始时不会失望。

我假设层次结构正是给定的三个层次。如果每个级别都需要一个具有自己名称的元素,那么就很难实现其他功能。同样出于这个原因,每个级别都必须有一个单独的模板,即使代码在很大程度上是相似的。否则,我们需要某种查找目录来查找“月”之后的内容,例如

(编辑)
还假设每个数据元素(一年除外)都有一个“父”数据元素;i、 e.在转换过程中不必创建中间元素

XSLT1.0

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

<xsl:template match="/root">
    <xsl:copy>
        <xsl:apply-templates 
            select="data[not(contains(., '/'))]" 
            mode="year"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="data" mode="year">
    <year value="{.}">
    <xsl:variable name="dir" select="concat(., '/')" />
        <xsl:apply-templates 
            select="/root/data
                [starts-with(., $dir)]
                [not (contains(substring-after(., $dir), '/'))]"
            mode="month"/>
    </year>
</xsl:template>

<xsl:template match="data" mode="month">
    <month value="{substring-after(., '/')}">
    <xsl:variable name="dir" select="concat(., '/')" />
        <xsl:apply-templates 
            select="/root/data
                [starts-with(., $dir)]
                [not (contains(substring-after(., $dir), '/'))]"
            mode="day"/>
    </month>
</xsl:template>

<xsl:template match="data" mode="day">
    <day value="{substring-after(substring-after(., '/'), '/')}">
    </day>
</xsl:template>

</xsl:stylesheet> 

应用于输入时,结果为:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <year value="2013">
      <month value="1">
         <day value="0"/>
         <day value="1"/>
         <day value="2"/>
      </month>
      <month value="2">
         <day value="0"/>
         <day value="1"/>
         <day value="2"/>
         <day value="3"/>
      </month>
   </year>
</root>


其中信息元素是我从中获得的关于每条路径的信息 在别的地方


我遗漏了这一部分,因为我根本不清楚这将如何工作。我希望您在开始时不会失望。

我假设层次结构正是给定的三个层次。如果每个级别都需要一个具有自己名称的元素,那么就很难实现其他功能。同样出于这个原因,每个级别都必须有一个单独的模板,即使代码在很大程度上是相似的。否则,我们需要某种查找目录来查找“月”之后的内容,例如

(编辑)
还假设每个数据元素(一年除外)都有一个“父”数据元素;i、 e.在转换过程中不必创建中间元素

XSLT1.0

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

<xsl:template match="/root">
    <xsl:copy>
        <xsl:apply-templates 
            select="data[not(contains(., '/'))]" 
            mode="year"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="data" mode="year">
    <year value="{.}">
    <xsl:variable name="dir" select="concat(., '/')" />
        <xsl:apply-templates 
            select="/root/data
                [starts-with(., $dir)]
                [not (contains(substring-after(., $dir), '/'))]"
            mode="month"/>
    </year>
</xsl:template>

<xsl:template match="data" mode="month">
    <month value="{substring-after(., '/')}">
    <xsl:variable name="dir" select="concat(., '/')" />
        <xsl:apply-templates 
            select="/root/data
                [starts-with(., $dir)]
                [not (contains(substring-after(., $dir), '/'))]"
            mode="day"/>
    </month>
</xsl:template>

<xsl:template match="data" mode="day">
    <day value="{substring-after(substring-after(., '/'), '/')}">
    </day>
</xsl:template>

</xsl:stylesheet> 

应用于输入时,结果为:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <year value="2013">
      <month value="1">
         <day value="0"/>
         <day value="1"/>
         <day value="2"/>
      </month>
      <month value="2">
         <day value="0"/>
         <day value="1"/>
         <day value="2"/>
         <day value="3"/>
      </month>
   </year>
</root>


其中信息元素是我从中获得的关于每条路径的信息 在别的地方


我遗漏了这一部分,因为我根本不清楚这将如何工作。我希望您在开始时不会失望。

我假设层次结构正是给定的三个层次。如果每个级别都需要一个具有自己名称的元素,那么就很难实现其他功能。同样出于这个原因,每个级别都必须有一个单独的模板,即使代码在很大程度上是相似的。否则,我们需要某种查找目录来查找o