通用XSLT 1.0从根节点获取不同的叶节点路径?

时间:2015-03-27 09:53:09

标签: xml xslt xpath

我有一个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>&#44;&#xA;</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

请帮忙。提前谢谢。

2 个答案:

答案 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="&#10;"/>
</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>&#10;</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>&#xA;</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