XSLT扁平结构到地方
我有一个现有的xml文件,数据格式如下。代码的前三个字母确定相同的组。XSLT扁平结构到地方
<Subjects>
<subject>
<code>ANT001000</code>
<literal>ANTIQUES/Americana</literal>
</subject>
<subject>
<code>ANT002000</code>
<literal>ANTIQUES/Art</literal>
</subject>
<subject>
<code>CKB100000</code>
<literal>COOKING/Beverages/General</literal>
</subject>
<subject>
<code>CKB006000</code>
<literal>COOKING/Beverages/Bartending</literal>
</subject>
</Subjects>
我需要改变它看起来像这样:
<node name="Antiques" id="1">
<node name="Americana" id="2" />
<node name="Art" id="3" />
</node>
<node name="Cooking" id="4">
<node name="Beverages " id="6" />
<node name="General" id="7" />
<node name="Bartending" id="8" />
</node>
</node>
我试了几种方法,但不能得到它的工作。任何想法将不胜感激。
由于
我建议在几次通过这样做:
第一遍将标记化在每个subject
的literal
元件列出的类别,并创建用于每一个category
节点。在给定的例子中,这将导致:
<category path="">ANTIQUES</category>
<category path="ANTIQUES/">Americana</category>
<category path="">ANTIQUES</category>
<category path="ANTIQUES/">Art</category>
<category path="">COOKING</category>
<category path="COOKING/">Beverages</category>
<category path="COOKING/Beverages/">General</category>
<category path="">COOKING</category>
<category path="COOKING/">Beverages</category>
<category path="COOKING/Beverages/">Bartending</category>
下一步将选择所有顶部的类别(即,类别与空@path属性):
<category path="">ANTIQUES</category>
<category path="">ANTIQUES</category>
<category path="">COOKING</category>
<category path="">COOKING</category>
,减少该进一步只包括不同的值:
<category path="">ANTIQUES</category>
<category path="">COOKING</category>
现在我们终于有一个像样的起点,在这里我们可以可以将模板应用到每个这样的类别做:
<xsl:template match="category">
<node name="{.}" id="{generate-id()}">
<xsl:apply-templates select="$child-categories"/>
</node>
</xsl:template>
其中$child-categories
代表其选择属性@path当前@path和电流值的串联匹配的类别的表达式。
我正在使用每个类别的完整路径,以防止在分类中分类名称不唯一的情况下出现错误的肯定匹配。
作为证明的概念,我已经写了下面的样式表,利用某些EXSLT扩展函数,即:exsl:节点集(),STR:记号化(),并设置:不同():
XSLT 1.0 + EXSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:set="http://exslt.org/sets"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="exsl set str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- first-pass -->
<xsl:variable name="categories">
<xsl:for-each select="/Subjects/subject">
<xsl:variable name="steps" select="str:tokenize(literal, '/')" />
<xsl:for-each select="$steps" >
<category>
<xsl:attribute name="path">
<xsl:for-each select="preceding-sibling::token" >
<xsl:value-of select="concat(., '/')" />
</xsl:for-each>
</xsl:attribute>
<xsl:value-of select="." />
</category>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="category-set" select="exsl:node-set($categories)/category" />
<xsl:template match="/">
<!-- output-->
<nodes>
<xsl:apply-templates select="set:distinct($category-set[not(string(@path))])"/>
</nodes>
</xsl:template>
<xsl:template match="category">
<node name="{.}" id="{generate-id()}">
<xsl:apply-templates select="set:distinct($category-set[@path=concat(current()/@path, current(), '/')])"/>
</node>
</xsl:template>
</xsl:stylesheet>
运行支持所有这些扩展函数(的libxslt)在处理器上时,结果是:
<?xml version="1.0" encoding="UTF-8"?>
<nodes>
<node name="ANTIQUES" id="idp4576">
<node name="Americana" id="idp4704"/>
<node name="Art" id="idp327680"/>
</node>
<node name="COOKING" id="idp25520">
<node name="Beverages" id="idp25648">
<node name="General" id="idp400976"/>
<node name="Bartending" id="idp27984"/>
</node>
</node>
</nodes>
谢谢迈克尔。我只能使用XSLT 1.0,因此无法使用您的建议解决方案。然而,我遵循java中的代码逻辑,它的工作就像一个魅力。谢谢 :) – user2118377 2015-02-23 22:24:07
请至少显示其中一种“多种方法”。谢谢! – 2015-02-09 18:43:19
这不会很简单。请指出是否使用XSLT 1.0或2.0。 - 代码的其余部分是否还有其他含义?(也许可以用来使其更容易)? – 2015-02-09 18:45:49
http://stackoverflow.com/help/someone-answers – 2015-02-19 10:17:31