我有一个我需要在树结构中制作的路径列表。另外,我需要添加一些与每个级别相关的特定信息。
示例输入
<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>
我需要看起来像这样的东西:
<root>
<year value="2013">
<info />
<month value="1">
<info />
<day value="0">
<info />
</day>
<day value="1">
<info />
</day>
...
</month>
...
</year>
...
</root>
如果信息元素是信息,我会从其他地方获得每条路径。
想我可能需要分组或其他东西,但之前从未使用它,而且通常只是卡在这里。不知道怎么攻击这个。任何帮助将不胜感激。
答案 0 :(得分:2)
使用XSL密钥可以相对容易地完成。 (此答案基于the one by michael.hor257k。)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="kLevel" match="data" use="
string-length(.) - string-length(translate(., '/', ''))
" />
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates mode="year" select="key('kLevel', 0)" />
</xsl:copy>
</xsl:template>
<xsl:template match="data" mode="year">
<year value="{.}">
<xsl:apply-templates mode="month" select="key('kLevel', 1)[starts-with(., concat(current(), '/'))]" />
</year>
</xsl:template>
<xsl:template match="data" mode="month">
<month value="{substring-after(., '/')}">
<xsl:apply-templates mode="day" select="key('kLevel', 2)[starts-with(., concat(current(), '/'))]" />
</month>
</xsl:template>
<xsl:template match="data" mode="day">
<day value="{substring-after(substring-after(., '/'), '/')}">
<info />
</day>
</xsl:template>
</xsl:stylesheet>
给出了
<root>
<year value="2013">
<month value="1">
<day value="0">
<info />
</day>
<day value="1">
<info />
</day>
<day value="2">
<info />
</day>
</month>
<month value="2">
<day value="0">
<info />
</day>
<day value="1">
<info />
</day>
<day value="2">
<info />
</day>
<day value="3">
<info />
</day>
</month>
</year>
</root>
答案 1 :(得分:1)
我假设层次结构正是给定的三个层次。如果每个级别都需要一个具有自己名称的元素,那么它就很难。由于这个原因,即使代码大致相似,也必须为每个级别都有一个单独的模板。否则,我们需要某种查找目录来查找“月”之后的内容,例如。
(编辑)
还假设每个数据元素 - 除了一年 - 具有“父”数据元素;即在转换过程中不必创建中间元素。
XSLT 1.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>
如果信息元素是信息,我会得到关于每条路径的信息 在其他地方。
我把这部分遗漏了,因为对我来说这根本不清楚。我希望你到达时不要失望。
答案 2 :(得分:0)
这是使用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>