【发布时间】:2013-12-10 18:16:21
【问题描述】:
我想创建一个仅包含在源文档中具有不同路径的节点名称的 XML。该值在这里并不重要,它可以是空值或虚拟值。换句话说,生成的文档应该只包含源文档的(节点)本质。
我找到了一个非常相似的问题的答案(链接: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() 之类的内置函数来获取当前节点的完整路径。
【问题讨论】:
-
你能用
node-set()吗? -
嗨竖琴!谢谢你的建议。我在这里不受任何约束。任何工作都很好。尽管如此,我还是想确保坚持使用 XSLT 的标准功能,而不是依赖于处理器的东西。所有标准 XSLT 1.0、2.0 或 3.0 实现中都应该有一个可行的解决方案。
-
使用完整路径是不够的。您可以使用有限的路径函数(例如
concat(local-name((ancestor::*)[1]), local-name((ancestor::*)[2]), local-name((ancestor::*)[3])))轻松测试这一点。问题是如果本地名称被视为组开始,模板只会下降到子树,因此甚至不会测试具有更深嵌套级别的后续子树。 -
我认为完全递归的
<for-each-group>可以完成这项工作。这需要 XSLT 2.0。当然,您也可以在 1.0 中使用 Muenchian Grouping 进行此操作,但为高效执行定义和不定数量的索引可能很困难。 -
嗨,马库斯!谢谢!如果我理解正确,您的意思是递归使用
之类的东西,对吗?我必须使用什么作为键(??? 部分)?与上面我的 xsl 1.0 转换中使用的 Muenchian 分组方法一样,我遇到了定义正确键的问题。有什么建议吗?