【问题标题】:How to display XSD validated XML using XSLT如何使用 XSLT 显示 XSD 验证的 XML
【发布时间】:2010-12-17 22:02:13
【问题描述】:

我已经和这个问题斗争了一段时间,还没有找到明确的答案。

据我了解,我可以将数据存储在 XML 文件中,使用 XSD 对其进行验证,然后使用 XSLT 整齐地显示数据。

但是,我在尝试执行 XPath 查询以选择我希望在 XSLT 中显示的数据时遇到了问题。当我使用像 './/' 或 '*' 这样的通用选择器时,我得到了我期望的结果。但是,当我尝试使用更具体的选择器,例如:'root/responses' 或任何其他变体时,我没有得到任何结果。

XSD 正确验证了 XML 文件,所以我猜我的数据至少在某种程度上是正确的。当我删除 XML 文件中的 XSD 引用,有效地删除数据验证时,我的 XPath 查询突然起作用了!有什么我想念的吗?我尝试向 XSLT 添加命名空间引用,但无济于事。

我在下面描述了 XSD、Sample XL 和 Sample XSLT。任何帮助或提示将不胜感激!


定义结构的 XSD 如下。这个 XSD 描述了一个简单的文档,它嵌套了三个元素,并应用了一个约束;响应代码的代码必须是唯一的。

<?xml version="1.0" encoding="utf-8"?>
    <xs:schema id="uitext"
        targetNamespace="http://foo.bar/responsecode.xsd"
        elementFormDefault="qualified"
        xmlns:responsecodes="http://foo.bar/responsecode.xsd"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">

        <xs:element name="root" type="responsecodes:rootType">
            <xs:key name="responseCode">
                <xs:selector xpath="responsecodes:responses/responsecodes:response">
                    <xs:annotation>
                        <xs:documentation>All defined responsecodes</xs:documentation>
                    </xs:annotation>
                </xs:selector>
                <xs:field xpath="@code">
                    <xs:annotation>
                        <xs:documentation>Unique responsecode</xs:documentation>
                    </xs:annotation>
                </xs:field>
            </xs:key>
        </xs:element>

        <xs:complexType name="rootType">
            <xs:sequence>
                <xs:element name="responses" minOccurs="1" maxOccurs="1" type="responsecodes:responseList">
                    <xs:annotation>
                        <xs:documentation>Defined responsecodes</xs:documentation>
                    </xs:annotation>
                </xs:element>
            </xs:sequence>
        </xs:complexType>

        <xs:complexType name="responseList">
            <xs:sequence>
                <xs:element name="response" minOccurs="0" maxOccurs="unbounded" type="responsecodes:response"/>
            </xs:sequence>
        </xs:complexType>

        <xs:complexType name="response">
            <xs:sequence>
                <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1">
                    <xs:annotation>
                        <xs:documentation>
                            Explains the use of the responsecode.
                        </xs:documentation>
                    </xs:annotation>
                </xs:element>
            </xs:sequence>
            <xs:attribute name="code" type="xs:string" use="required">
                <xs:annotation>
                    <xs:documentation>Unique code representing the response provided.</xs:documentation>
                </xs:annotation>
            </xs:attribute>
        </xs:complexType>
    </xs:schema>

XML 文档示例如下:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="responsecode.xsl"?>
<root xmlns="http://foo.bar/responsecode.xsd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://foo.bar/responsecode.xsd responsecode.xsd">
    <responses>
        <response code="firstCode">
            <description>Explanation of first code</description>
        </response>
        <response code="secondCode">
            <description>Explanation of second code</description>
        </response>
        <response code="thirdCode">
            <description>Explanation of third code.</description>
        </response>
    </responses>
</root>

XML 文件中引用的测试 XSLT 文档如下。 (这将以类似于 VS2008 枚举定义的格式显示所提到的代码,但除此之外)

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html><body><h2>Responses</h2>

                <xsl:for-each select="root/responses/response">
                    <xsl:choose>
                        <xsl:when test="description != ''">
                            <br/>'''&lt;description&gt;
                            <br/>'''<xsl:value-of select="description" />
                            <br/>'''&lt;/description&gt;
                        </xsl:when>
                    </xsl:choose>
                    <br/>
                    <xsl:value-of select="@code" />

                </xsl:for-each>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

【问题讨论】:

    标签: xml xslt xpath xsd namespaces


    【解决方案1】:

    简单的问题:您的 XML 元素位于 XSLT 不知道的名称空间中。

    <root xmlns="http://foo.bar/responsecode.xsd">
      <responses>
        <!-- ... -->
      </responses>
    </root>
    

    将您的 &lt;root&gt; 和所有后代元素放入 "http://foo.bar/responsecode.xsd" 命名空间。

    像这样更改您的 XSL:

    <xsl:stylesheet 
      version="1.0" 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:foo="http://foo.bar/responsecode.xsd"
      exclude-result-prefixes="foo"
    >
      <xsl:template match="/">
        <html>
          <body>
            <h2>Responses</h2>
            <xsl:for-each select="foo:root/foo:responses/foo:response">
              <!-- ... -->
            </xsl:for-each>
          </body>
        </html>
      </xsl:template>
    </xsl:stylesheet>
    

    注意命名空间是如何声明和赋予前缀的。稍后,该名称空间中的所有节点都使用该前缀进行引用。 exclude-result-prefixes 用于确保命名空间不会不必要地出现在输出中。

    【讨论】:

      【解决方案2】:

      这是一个命名空间问题。您必须为http://foo.bar/responsecode.xsd 添加命名空间声明,并使用该命名空间引用元素。 More info can be found here.

      所以基本上你需要这样的东西:

      <xsl:stylesheet
        version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
        xmlns:test="http://foo.bar/responsecode.xsd">
        <xsl:template match="/">
          <html>
            <body>
              <h2>Responses</h2>
      
              <xsl:for-each select="test:root/test:responses/test:response">
                <xsl:choose>
                  <xsl:when test="test:description != ''">
                    <br/>'''&lt;description&gt;
                    <br/>'''<xsl:value-of select="test:description" />
                    <br/>'''&lt;/description&gt;
                  </xsl:when>
                </xsl:choose>
                <br/>
                <xsl:value-of select="@code" />
      
              </xsl:for-each>
            </body>
          </html>
        </xsl:template>
      </xsl:stylesheet>
      

      注意xsl:stylesheet 属性中的“xmlns:test”。我对此进行了测试,它确实有效。

      【讨论】:

        【解决方案3】:

        当然,只要您发布问题,您自己就会找到答案!

        原来命名空间引用中一定有错字。仔细检查这篇文章后:

        xslt-transform-xml-with-namespaces

        这基本上是同一个问题。 (我在发布之前搜索过......老实说!),我尝试再次添加命名空间引用,这一次它完美无缺!

        我将命名空间映射到前缀“nsm”(NameSpaceMapping),瞧!

        <?xml version="1.0" encoding="iso-8859-1"?>
        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:nsm="http://foo.bar/responsecode.xsd">
            <xsl:template match="/">
                <html><body><h2>Responses</h2>
        
                                <xsl:for-each select="nsm:root/nsm:responses/nsm:response">
                                        <xsl:choose>
                                                <xsl:when test="nsm:description != ''">
                                                        <br/>'''&lt;description&gt;
                                                        <br/>'''<xsl:value-of select="nsm:description" />
                                                        <br/>'''&lt;/description&gt;
                                                </xsl:when>
                                        </xsl:choose>
                                        <br/>
                                        <xsl:value-of select="@code" />
        
                                </xsl:for-each>
                        </body>
                </html>
            </xsl:template>
        </xsl:stylesheet>
        

        【讨论】:

        • 哈哈!你用你自己的答案打败了我几秒钟。进展顺利!
        • 很好地自己找到答案。 +1
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-29
        • 1970-01-01
        相关资源
        最近更新 更多