通用 XSLT 1.0 从根节点获取不同的叶节点路径?
Generic XSLT 1.0 to get distinct leaf node path from root node?
我有一个 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
。
请帮忙。提前致谢。
SAXON 9.3.0.5 from Saxonica
很好:这意味着您可以使用 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>
编辑:
I got a problem. I have one other server whose XSLT processor is
Apache Software Foundation and I am not able to transform it.
对于 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>
这个 XSLT 1.0 解决方案怎么样?不需要两个不同的样式表!
- No extension function used (no
exslt set:distinct()
, no exslt:node-set()
)
- Completely portable between any two XSLT processors -- due to the above
- Single-pass (no multi-pass processing, no intermediate results and no need to convert RTFs to temporary trees)
- No explicit conditional XSLT instructions and no
<xsl:for-each>
- Adjustable to a maximum depth -- possibly a depth of 30 will work in 99.999% of the cases
- Using keys (Muenchian grouping) and thus very fast
<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
我有一个 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
。
请帮忙。提前致谢。
SAXON 9.3.0.5 from Saxonica
很好:这意味着您可以使用 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>
编辑:
I got a problem. I have one other server whose XSLT processor is Apache Software Foundation and I am not able to transform it.
对于 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>
这个 XSLT 1.0 解决方案怎么样?不需要两个不同的样式表!
- No extension function used (no
exslt set:distinct()
, noexslt:node-set()
)- Completely portable between any two XSLT processors -- due to the above
- Single-pass (no multi-pass processing, no intermediate results and no need to convert RTFs to temporary trees)
- No explicit conditional XSLT instructions and no
<xsl:for-each>
- Adjustable to a maximum depth -- possibly a depth of 30 will work in 99.999% of the cases
- Using keys (Muenchian grouping) and thus very fast
<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