Как отобразить проверенный XSD XML с использованием XSLT - PullRequest
7 голосов
/ 18 ноября 2009

Я боролся с этим в течение некоторого времени и пока не смог найти четкого ответа на этот вопрос.

Как я правильно понимаю, я могу сохранить данные в файле XML, проверить их с помощью XSD, а затем аккуратно отобразить данные с помощью XSLT.

Однако у меня возникли проблемы при попытке выполнить запросы XPath для выбора данных, которые я хочу отобразить в моем XSLT. Когда я использую общие селекторы, такие как «.//» или «*», я получаю ожидаемые результаты. Однако, когда я пытаюсь использовать более конкретные селекторы, такие как: «корень / ответы» или любой другой вариант, я не получаю результатов.

Файл XML правильно проверен XSD, поэтому я думаю, что мои данные, по крайней мере, в некоторой степени верны. Когда я удаляю ссылку XSD в файле XML, фактически удаляя проверку данных, мои запросы XPath неожиданно работают! Я что-то упускаю? Я пытался добавить ссылки на пространство имен в XSLT, но безрезультатно.

Я описал XSD, Образец XL и Образец 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>

Тестовый документ XSLT, указанный в файле XML, выглядит следующим образом. (Это будет отображать коды, упомянутые в формате, который будет напоминать определения перечисления 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>

Ответы [ 3 ]

9 голосов
/ 18 ноября 2009

Простая проблема: ваши элементы XML находятся в пространстве имен, о котором ваш XSLT ничего не знает.

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

помещает ваш <root> и все дочерние элементы в пространство имен "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 используется для того, чтобы пространство имен не появлялось в выходных данных без необходимости.

7 голосов
/ 18 ноября 2009

И, конечно же, как только вы отправите вопрос, вы сами найдете ответ!

Оказывается, в ссылке на пространство имен должна была быть опечатка. После двойной проверки этого сообщения:

XSLT-преобразование-XML-с-пространствами имен

Который в основном оказывается тем же вопросом. (Я искал перед публикацией .... честно!), Я попытался снова добавить ссылку на пространство имен, и на этот раз это работало безупречно!

Я сопоставил пространство имен с префиксом '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>
4 голосов
/ 18 ноября 2009

Это проблема пространства имен. Вам нужно будет добавить объявление пространства имен для http://foo.bar/responsecode.xsd и ссылаться на элементы, использующие это пространство имен. Более подробную информацию можно найти здесь .

Так что в основном вам нужно что-то вроде этого:

<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>

Обратите внимание на «xmlns: test» в атрибутах xsl:stylesheet. Я дал это испытание, и оно работает.

...