使用XPath获取/记录上下文节点的子级

时间:2011-02-09 20:00:04

标签: xml xslt xpath

关于使用XSLT列出XML文件中的每个节点的another thread,Alejandro提供了this useful piece of XPath 2.0 code:

编辑:我的样式表现在使用Alejandro在评论中发布的代码的修改版本。它报告元素的@name属性。

我已经对其进行了大量修改,以应用于.xsd架构,如下所示:

示例模式

(此source的简化版)

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:annotation>
    <xsd:documentation xml:lang="en">
 Purchase order schema for Example.com.
 Copyright 2000 Example.com. All rights reserved.
</xsd:documentation>
</xsd:annotation>
<xsd:element name="comment" type="xsd:string">
    <xsd:annotation>
        <xsd:documentation>doc for comment</xsd:documentation>
    </xsd:annotation>
</xsd:element>
<xsd:complexType name="USAddress">
    <xsd:annotation>
        <xsd:documentation>doc for USAddress</xsd:documentation>
    </xsd:annotation>
    <xsd:sequence>
        <xsd:element name="name" type="xsd:string"/>
        <xsd:element name="street" type="xsd:string"/>
        <xsd:element name="city" type="xsd:string"/>
        <xsd:element name="state" type="xsd:string"/>
        <xsd:element name="zip" type="xsd:decimal"/>
    </xsd:sequence>
    <xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/>
</xsd:complexType>
<!-- Stock Keeping Unit, a code for identifying products -->
<xsd:simpleType name="SKU">
    <xsd:annotation>
        <xsd:documentation>doc for SKU</xsd:documentation>
    </xsd:annotation>
    <xsd:restriction base="xsd:string">
        <xsd:pattern value="\d{3}-[A-Z]{2}"/>
    </xsd:restriction>
</xsd:simpleType>
</xsd:schema>
我的XSLT样式表:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:template match="*|@*">
<xsl:value-of select="
string-join(
distinct-values(
(//*|//@*)
/string-join(
(ancestor::node()/name(),
if (self::attribute())
    then concat('@',name())
    else if (self::*[@name]) 
        then concat(name(),'[@name=&quot;',@name,'&quot;]')
        else name()),
'/')),
'&#xA;')
"/>
    </xsl:template>
    </xsl:stylesheet>
结果:
/xsd:schema
/xsd:schema/xsd:annotation
/xsd:schema/xsd:annotation/xsd:documentation
/xsd:schema/xsd:annotation/xsd:documentation/@xml:lang
/xsd:schema/xsd:element[@name="comment"]
/xsd:schema/xsd:element/@name
/xsd:schema/xsd:element/@type
/xsd:schema/xsd:element/xsd:annotation
/xsd:schema/xsd:element/xsd:annotation/xsd:documentation
/xsd:schema/xsd:complexType[@name="USAddress"]
/xsd:schema/xsd:complexType/@name
/xsd:schema/xsd:complexType/xsd:annotation
/xsd:schema/xsd:complexType/xsd:annotation/xsd:documentation
/xsd:schema/xsd:complexType/xsd:sequence
/xsd:schema/xsd:complexType/xsd:sequence/xsd:element[@name="name"]
/xsd:schema/xsd:complexType/xsd:sequence/xsd:element/@name
/xsd:schema/xsd:complexType/xsd:sequence/xsd:element/@type
/xsd:schema/xsd:complexType/xsd:sequence/xsd:element[@name="street"]
/xsd:schema/xsd:complexType/xsd:sequence/xsd:element[@name="city"]
/xsd:schema/xsd:complexType/xsd:sequence/xsd:element[@name="state"]
/xsd:schema/xsd:complexType/xsd:sequence/xsd:element[@name="zip"]
/xsd:schema/xsd:complexType/xsd:attribute[@name="country"]
/xsd:schema/xsd:complexType/xsd:attribute/@name
/xsd:schema/xsd:complexType/xsd:attribute/@type
/xsd:schema/xsd:complexType/xsd:attribute/@fixed
/xsd:schema/xsd:simpleType[@name="SKU"]
/xsd:schema/xsd:simpleType/@name
/xsd:schema/xsd:simpleType/xsd:annotation
/xsd:schema/xsd:simpleType/xsd:annotation/xsd:documentation
/xsd:schema/xsd:simpleType/xsd:restriction
/xsd:schema/xsd:simpleType/xsd:restriction/@base
/xsd:schema/xsd:simpleType/xsd:restriction/xsd:pattern
/xsd:schema/xsd:simpleType/xsd:restriction/xsd:pattern/@value

出于此问题的目的,此输出正常。

现在,而不是问“我的代码有什么问题?”我只想问一下从实际工作的基础状态开始的最佳方法。

我需要添加一个子句,对于/xsd:documentation孙子的每一行,都附加<xsd:documentation>foo</xsd:documentation>的文本。所以这一行:

/xsd:schema/xsd:element[@name="comment"]

变为:

/xsd:schema/xsd:element[@name="comment"] | doc for comment

谢谢, 马特

2 个答案:

答案 0 :(得分:3)

解决方案很简单

0.1。在样式表中定义xsd命名空间:

<xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>

0.2。变化:

.//documentation

.//xsd:documentation

BTW,这是错误的

//xsd|//@*

文档中没有名为xsd的元素。可能你想要:

//xsd:*|//@* 

此外,无需在属性上使用local-name(),只需name()即可。

第二次观察:

亚历杭德罗的解决方案没有任何问题。应用于提供的XML文档,它会生成以下正确的输出:

/xsd:schema
/xsd:schema/xsd:annotation
/xsd:schema/xsd:annotation/xsd:documentation
/xsd:schema/xsd:annotation/xsd:documentation/@xml:lang
/xsd:schema/xsd:element
/xsd:schema/xsd:element/@name
/xsd:schema/xsd:element/@type
/xsd:schema/xsd:element/xsd:annotation
/xsd:schema/xsd:element/xsd:annotation/xsd:documentation
/xsd:schema/xsd:complexType
/xsd:schema/xsd:complexType/@name
/xsd:schema/xsd:complexType/xsd:sequence
/xsd:schema/xsd:complexType/xsd:sequence/xsd:element
/xsd:schema/xsd:complexType/xsd:sequence/xsd:element/@name
/xsd:schema/xsd:complexType/xsd:sequence/xsd:element/@type
/xsd:schema/xsd:complexType/xsd:attribute
/xsd:schema/xsd:complexType/xsd:attribute/@name
/xsd:schema/xsd:complexType/xsd:attribute/@type
/xsd:schema/xsd:complexType/xsd:attribute/@fixed
/xsd:schema/xsd:complexType/xsd:annotation
/xsd:schema/xsd:complexType/xsd:annotation/xsd:documentation
/xsd:schema/xsd:simpleType
/xsd:schema/xsd:simpleType/@name
/xsd:schema/xsd:simpleType/xsd:restriction
/xsd:schema/xsd:simpleType/xsd:restriction/@base
/xsd:schema/xsd:simpleType/xsd:restriction/xsd:pattern
/xsd:schema/xsd:simpleType/xsd:restriction/xsd:pattern/@value
/xsd:schema/xsd:simpleType/xsd:annotation
/xsd:schema/xsd:simpleType/xsd:annotation/xsd:documentation

答案 1 :(得分:0)

.//xsd:documentation试图获取架构中的所有文档子项。我使用./xsd:documentation来解决问题。

在测试后报告任何元素的文档以查看它是否属性的新子句:

concat(
if (self::*[@name]) 
then @name
else name()
, ./xsd:documentation)

感谢大家的帮助。