我有一个像这样的xml文档:
<Catalogs>
<Catalog>
<Code>x</Code>
<Name>Ox</Name>
<Categories>
<Category>
<Id>9245</Id>
<Name>a</Name>
<Category>
<Id>9247</Id>
<Name>x</Name>
</Category>
</Category>
<Category>
<Id>9250</Id>
<Name>x</Name>
<Category>
<Id>9252</Id>
<Name>x</Name>
</Category>
<Category>
<Id>9258</Id>
<Name>x</Name>
<Category>
<Id>9260</Id>
<Name>x</Name>
</Category>
<Category>
<Id>9261</Id>
<Name>x</Name>
</Category>
<Category>
<Id>9261</Id>
<Name>x</Name>
</Category>
</Category>
</Category>
<Category>
<Id>9251</Id>
<Name>x</Name>
<Category>
<Id>9253</Id>
<Name>x</Name>
</Category>
</Category>
</Categories>
</Catalog>
</Catalogs>
我想将Category-tags的每个子集包装到一个集合标签(Categories)中。 这里的问题是这是一个递归树,树的深度是未知的。
我尝试使用xslt转换,但还没有成功。我的尝试
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Category">
<Categories><xsl:apply-templates select="Category"/></Categories>
</xsl:template>
</xsl:stylesheet>
只需用空的分类标签替换所有孩子。
示例输出应该是这样的:
<Catalogs>
<Catalog>
<Code>x</Code>
<Name>Ox</Name>
<Categories>
<Category>
<Id>9245</Id>
<Name>a</Name>
<Categories>
<Category>
<Id>9247</Id>
<Name>x</Name>
</Category>
</Categories>
</Category>
<Category>
<Id>9250</Id>
<Name>x</Name>
<Categories>
<Category>
<Id>9252</Id>
<Name>x</Name>
</Category>
<Category>
<Id>9258</Id>
<Name>x</Name>
<Categories>
<Category>
<Id>9260</Id>
<Name>x</Name>
</Category>
<Category>
<Id>9261</Id>
<Name>x</Name>
</Category>
<Category>
<Id>9261</Id>
<Name>x</Name>
</Category>
</Categories>
</Category>
</Categories>
</Category>
<Category>
<Id>9251</Id>
<Name>x</Name>
<Categories>
<Category>
<Id>9253</Id>
<Name>x</Name>
</Category>
</Categories>
</Category>
</Categories>
</Catalog>
</Catalogs>
任何指针(或完整的解决方案)都将不胜感激。
答案 0 :(得分:4)
首先,您应该在XSLT身份模板之上构建XSLT,该模板将复制XML中没有明确匹配模板的所有节点
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
如果没有这个,XSLT的内置模板将启动,只输出它找到的任何元素的文本。
您的XSLT的另一个问题是,当您匹配类别元素时,您正在执行<xsl:apply-templates select="Category"/>
,这意味着您只是告诉XSLT查找任何类别< / strong>元素是当前元素的子元素。
您可以采取的一种方法是让您的模板与任何类别元素的父级匹配(不包括类别元素)
<xsl:template match="*[not(self::Categories)][Category]">
然后,在此内容中,您可以复制元素,并在其中插入类别元素以包含所有类别元素
<xsl:copy>
<xsl:apply-templates select="@*|node()[not(self::Category)]"/>
<Categories>
<xsl:apply-templates select="Category"/>
</Categories>
</xsl:copy>
在这种情况下,这是完整的XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*[not(self::Categories)][Category]">
<xsl:copy>
<xsl:apply-templates select="@*|node()[not(self::Category)]"/>
<Categories>
<xsl:apply-templates select="Category"/>
</Categories>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这种方法的一个缺点是,如果您在父级中的类别之后出现任何元素,这些元素将被移动到创建的类别元素之前
另一种方法是匹配父项中 Category 元素的第一次出现,然后复制该元素及其所有后续兄弟
尝试这个XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Category[1]">
<Categories>
<xsl:apply-templates select="self::*|following-sibling::Category" mode="categories"/>
</Categories>
</xsl:template>
<xsl:template match="Category" mode="categories">
<xsl:call-template name="identity" />
</xsl:template>
<xsl:template match="Category" />
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
关于这种方法需要注意两点。首先,在查找与节点匹配的模板时,XSLT将始终优先考虑更具体的模板匹配。因此,对于第一个类别元素,“类别[1]”将被用于“类别”。
其次,请注意此处使用模式,否则您将有两个模板匹配具有相同优先级的“类别”,这是不允许的。