我想创建一个只包含节点名称的XML,这些节点名称在源文档中找到了不同的路径。这里的值并不重要,它可以是空的或虚拟值。换句话说,生成的文档应该只包含源文档的(node-)本质。
我找到了一个答案(链接:How to list complete XML document using XSLT)到一个指向正确方向的非常相似的问题,但并不完全是我想要的。
使用上述帖子的修改示例:
来源文件:
<?xml version="1.0" encoding="UTF-8"?>
<MediaCatalog name="AccessoriesCatalog">
<Category Definition="AccessoriesCategory"
name="1532" id="1532">
</Category>
<Category Definition="AccessoriesCategory"
name="16115" id="16115">
<ParentCategory>1532</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16116" id="16116">
<ParentCategory>16115</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16126" id="16126">
<ParentCategory>16115</ParentCategory>
<genre>
<id>17</id>
<name>Fairy Tales</name>
</genre>
</Category>
<Category Definition="AccessoriesCategory"
name="16131" id="16131">
<ParentCategory>1532</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16132" id="16132">
<ParentCategory>16131</ParentCategory>
<language>
<id>1</id>
<name>English</name>
<shortName>EN</shortName>
</language>
</Category>
<Category Definition="AccessoriesCategory"
name="16136" id="16136">
<ParentCategory>16131</ParentCategory>
<genre>
<id>18</id>
<name>Thriller</name>
</genre>
</Category>
<Category Definition="AccessoriesCategory"
name="16139" id="16139">
<ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16144" id="16144">
<ParentCategory>16131</ParentCategory>
<subCategory>
<label>
<id>444</id>
<name>label444</name>
</label>
</subCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16195" id="16195">
<ParentCategory>16131</ParentCategory>
</Category>
</MediaCatalog>
生成的文档应如下所示:
<MediaCatalog>
<Category>
<ParentCategory>
</ParentCategory>
<genre>
<id></id>
<name></name>
</genre>
<language>
<id></id>
<name></name>
<shortName></shortName>
</language>
<subCategory>
<label>
<id></id>
<name></name>
</label>
</subCategory>
</Category>
</MediaCatalog>
根据我发现的类似问题的答案,我提出了以下转变来实现这一目标:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kElemByName" match="*" use="local-name()"/>
<xsl:template match="
*[generate-id()
=
generate-id(key('kElemByName', local-name())[1])
]">
<xsl:value-of select="concat('<', local-name(), '>', '
')" disable-output-escaping="yes" />
<xsl:apply-templates select="*"/>
<xsl:value-of select="concat('</', local-name(), '>', '
')" disable-output-escaping="yes" />
</xsl:template>
<xsl:template match="text()">
</xsl:template>
</xsl:stylesheet>
然而,这并没有给出正确的答案,因为Muenchian分组方法的密钥仅基于使用函数local-name()的节点名称。
因此将此应用于上面的源xml,而不是正确的输出:
<?xml version="1.0" encoding="UTF-8"?>
<MediaCatalog>
<Category>
</Category>
<ParentCategory>
</ParentCategory>
<genre>
<id>
</id>
<name>
</name>
</genre>
<language>
<shortName>
</shortName>
</language>
<subCategory>
<label>
</label>
</subCategory>
</MediaCatalog>
为了创建正确的输出,必须使用完整的节点路径作为密钥,而不是仅使用节点名称。问题是如何在XSLT中实现这一点,因为据我所知,没有内置函数,如getFullPath(),以获取当前节点的完整路径。
答案 0 :(得分:0)
以下XSLT生成所需的输出(除了不能很好地缩进的事实):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<!-- Template for recursive handling of the child nodes.
Note that these nodes originate from different parents belonging to the same group!
This is important since we have to scan ALL sub trees of the a group and not only the first one!
-->
<xsl:template name="descend">
<xsl:param name="nodes"/>
<xsl:for-each-group select="$nodes" group-by="local-name()">
<xsl:value-of select="concat('<', current-grouping-key(), '>', '
')" disable-output-escaping="yes" />
<xsl:call-template name="descend">
<!-- Call recursively. -->
<xsl:with-param name="nodes" select="current-group()/*"/>
</xsl:call-template>
<xsl:value-of select="concat('</', current-grouping-key(), '>', '
')" disable-output-escaping="yes" />
</xsl:for-each-group>
</xsl:template>
<!-- Start the recursion with the children of the root node. -->
<xsl:template match="/">
<xsl:call-template name="descend">
<xsl:with-param name="nodes" select="*"/>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>