我有一个xml文档,我试图从root的孩子那里得到不同的叶节点路径。
XML :
<?xml version="1.0" encoding="utf-8" ?>
<root>
<class>
<city>Test Data</city>
<activity_version_id>Test Data</activity_version_id>
<event_id>Test Data</event_id>
</class>
<class>
<city>Test Data</city>
<activity_version_id>Test Data</activity_version_id>
<event_id>Test Data</event_id>
</class>
</root>
XSL :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="no" />
<xsl:template match="*[not(*)]">
<xsl:for-each select="ancestor-or-self::*">
<xsl:if test="name(/*) != name(current())">
<xsl:value-of select="name()"/>
<xsl:if test="count(descendant::*) != 0">
<xsl:value-of select="concat('.','')"/>
</xsl:if>
</xsl:if>
</xsl:for-each>
<xsl:text>,
</xsl:text>
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates select="*"/>
</xsl:template>
</xsl:stylesheet>
实际
class.city,
class.activity_version_id,
class.event_id,
class.city,
class.activity_version_id
class.event_id
但我想只获得不同的节点路径,即不同的节点路径
class.city
class.activity_version_id
class.event_id
XSLT处理器为Apache Software Foundation
。
请帮忙。提前谢谢。
答案 0 :(得分:3)
来自Saxonica的SAXON 9.3.0.5
这很好:这意味着你可以使用XSLT 2.0。尝试:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:variable name="paths">
<xsl:apply-templates select="/*"/>
</xsl:variable>
<xsl:template match="/">
<xsl:value-of select="distinct-values($paths/path)" separator=" "/>
</xsl:template>
<xsl:template match="*[not(*)]">
<path>
<xsl:value-of select="ancestor-or-self::*/name()" separator="."/>
</path>
</xsl:template>
</xsl:stylesheet>
我遇到了问题。我有另一个服务器的XSLT处理器 Apache Software Foundation,我无法对其进行转换。
对于Apache Xalan,请尝试:
XSLT 1.0
<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"
extension-element-prefixes="exsl set">
<xsl:output method="text" encoding="utf-8"/>
<xsl:variable name="paths">
<xsl:apply-templates select="/*"/>
</xsl:variable>
<xsl:template match="/">
<xsl:for-each select="set:distinct(exsl:node-set($paths)/path)">
<xsl:value-of select="."/>
<xsl:if test="position()!=last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="*[not(*)]">
<path>
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="name()"/>
<xsl:if test="position()!=last()">
<xsl:text>.</xsl:text>
</xsl:if>
</xsl:for-each>
</path>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
这个XSLT 1.0解决方案怎么样?不需要两种不同的样式表!
- 未使用扩展功能(无
exslt set:distinct()
,无exslt:node-set()
)- 在任何两个XSLT处理器之间完全可移植 - 由于上述
- 单次传递(无多次传递处理,无中间结果,无需将RTF转换为临时树)
- 没有明确的条件XSLT指令,也没有
<xsl:for-each>
- 可调整到最大深度 - 可能深度为30将在99.999%的情况下起作用
- 使用密钥( Muenchian 分组)因此非常快
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kNodeByPath" match="*[not(*)]"
use="concat(name(), '/', name(..), '/', name(../..), '/', name(../../..),
'/', name(../../../..), '/', name(../../../../..))"/>
<xsl:template match=
"*[not(*)][generate-id()
= generate-id(key('kNodeByPath',
concat(name(), '/', name(..), '/', name(../..),
'/', name(../../..), '/', name(../../../..),
'/', name(../../../../..)))[1])
]">
<xsl:apply-templates select="ancestor::*[parent::*]" mode="path"/>
<xsl:value-of select="name()"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="*" mode="path">
<xsl:value-of select="concat(name(), '.')"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
在提供的源XML文档上应用此转换时:
<root>
<class>
<city>Test Data</city>
<activity_version_id>Test Data</activity_version_id>
<event_id>Test Data</event_id>
</class>
<class>
<city>Test Data</city>
<activity_version_id>Test Data</activity_version_id>
<event_id>Test Data</event_id>
</class>
</root>
产生了想要的正确结果:
class.city
class.activity_version_id
class.event_id