XML-схема: могу ли я сделать некоторые значения атрибута обязательными, но все же разрешить другие значения?

(примечание: Я не могу изменить структуру XML я получаю. Я могу только изменить то, как я подтверждаю это.)

предположим, я могу получить XML следующим образом:

<Address Field="Street" Value="123 Main"/>
<Address Field="StreetPartTwo" Value="Unit B"/>
<Address Field="State" Value="CO"/>
<Address Field="Zip" Value="80020"/>
<Address Field="SomeOtherCrazyValue" Value="Foo"/>

мне нужно создать схему XSD, которая проверяет, что "улица", "состояние" и "Zip"должны присутствовать. Но мне все равно, если" StreetPartTwo "и/или" SomeOtherCrazyValue " тоже присутствуют.

Если бы я знал, что только три меня волнует, могут быть включены (и что каждый будет включен только один раз), я мог бы сделать что-то вроде этого:

<xs:element name="Address" type="addressType" maxOccurs="unbounded" minOccurs="3"/>

<xs:complexType name="addressType">
  <xs:attribute name="Field" use="required">
    <xs:simpleType>
      <xs:restriction base="xs:string">
        <xs:enumeration value="Street"/>
        <xs:enumeration value="State"/>
        <xs:enumeration value="Zip"/>
      </xs:restriction>
    </xs:simpleType>
  </xs:attribute>
</xs:complexType>

но это не будет работать с моим случаем, потому что я также могу получить те другие элементы адреса (которые также имеют атрибуты "поля"), которые меня не волнуют.

любые идеи, как я могу гарантировать, что материал, о котором я забочусь, присутствует, но пусть и другие вещи тоже?

ТИА! Шон!--5-->

2 ответов


вы не можете выполнить проверку, которую вы ищете, только с XML-схемой.

по словам "XML-схема Часть 1: структуры" спецификация ...

когда две или более частицы, содержащиеся прямо или косвенно в {particles} модельной группы, имеют идентично именованные объявления элементов в качестве их {term} определения типов этих объявлений должны быть тот же.

это не значит, что вы не можете построить схема, которая будет проверять правильный документ. Это означает, что вы не можете построить схему, которая не будет проверяться на некоторых неправильных документах. И когда я говорю "неверно", я имею в виду документы, которые нарушают ограничения, указанные вами на английском языке.

например, предположим, что у вас есть документ, который включает в себя три элемента улицы, например:

<Address Field="Street" Value="123 Main"/> 
<Address Field="Street" Value="456 Main"/> 
<Address Field="Street" Value="789 Main"/> 
<Address Field="SomeOtherCrazyValue" Value="Foo"/> 

согласно вашей схеме, этот документ является действительным адресом. Можно добавить xs: уникальный ограничение вашей схемы, чтобы она отклоняла такие сломанные документы. Но даже с xs: unique, проверка против такой схемы объявит, что некоторые другие неправильные документы действительны - например, документ с тремя <Address> элементы, каждый из которых имеет уникальный , а не Field="Zip".

фактически невозможно создать схему W3C XML, которая формально кодирует ваши заявленные ограничения. The <xs:all> элемент почти получает вас threre, но это относится только к элементам, а не к атрибутам. И он не может использоваться с расширением, поэтому вы не можете сказать в схеме W3C XML: "все эти элементы в любом порядке плюс любые другие".


чтобы выполнить проверку, которую вы ищете, ваши варианты:

  1. положитесь на что-то другое, чем XML-схема,
  2. выполните проверку в несколько шагов, используя схему XML для первого шага, и что-то еще для второго шага.

для первого варианта, я думаю, вы могли бы использовать Relax NG, чтобы сделать это. Недостатком этого является то, что это не стандарт, и, насколько я могу судить, он не поддерживается и не растет. Это все равно что изучать гэльский язык, чтобы выразить мысль. Нет ничего плохого в гэльском, но это своего рода лингвистический тупик, и я думаю, RelaxNG тоже.

для второго варианта, подход будет для проверки вашей схемы в качестве первого шага, а затем, как второй шаг:

A. примените преобразование XSL, которое преобразует <Address> элементы в элементы, названные по значению их атрибута поля. Результат этого преобразования будет выглядеть следующим образом:

<root>
  <Street Value="101 Bellavista Drive"/>
  <State  Value="Confusion"/>
  <Zip    Value="10101"/>
</root>

B. проверьте вывод этого преобразования по другой схеме, которая выглядит примерно так:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified">
  <xs:element name="root">
    <xs:complexType>
      <xs:all>
        <xs:element maxOccurs="1" minOccurs="1" ref="Street" />
        <xs:element maxOccurs="1" minOccurs="1" ref="State" />
        <xs:element maxOccurs="1" minOccurs="1" ref="Zip" />
      </xs:all>
    </xs:complexType>
  </xs:element>

  <xs:element name="Street">
    <xs:complexType>
      <xs:attribute name="Value" use="required" type="xs:string"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="State">
    <xs:complexType>
      <xs:attribute name="Value" use="required" type="xs:string"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="Zip">
    <xs:complexType>
      <xs:attribute name="Value" use="required" type="xs:string"/>
    </xs:complexType>
  </xs:element>

</xs:schema>

вам нужно будет расширить эту схему для обработки других такие элементы, как <SomeOtherCrazyValue> в выводе преобразования. Или вы можете структурировать преобразование xsl, чтобы просто не испускать элементы, которые не являются одним из {State,Street, Zip}.

чтобы быть ясным, я понимаю, что вы не можете изменить XML, который вы получаете. Такой подход не требует. Он просто использует фанки 2 этапа проверки. После завершения второго шага проверки вы можете отказаться от результата преобразования.


редактировать - На самом деле, Шон, думая об этом снова, вы можете просто использовать шаг B. предположим, что ваше преобразование XSL просто выводит только из документа <Address> элементы, которые не имеют State, Street или Zip для значения атрибута поля. Другими словами, не было бы <Address Field="SomeOtherCrazyValue"...>. Результат этого преобразования может быть проверен с помощью вашей схемы, используя maxOccurs= "3", minOccurs=" 3 " и xs:unique.


у меня такая же проблема, как и у вас, но преодолена трюком.

запрос XML

<request>
    <url>Abcd</url>
    <base-url>XXXXX/</base-url>
    <args src="url">
        <arg name="languageCode">NL</arg>
        <arg name="version">1</arg>
        <arg name="offerId">10</arg>
        <arg name="rewardId">1234</arg>
    </args>
</request>

теперь используйте xslt и преобразуйте его,

код XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8"
indent="yes" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="arg">
<xsl:element name="{@name}">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>

XML становится

<?xml version="1.0" encoding="UTF-8"?>
<request>

    <url>abcd</url>
    <base-url>XXXXXXX</base-url>
    <args src="url">
        <languageCode>NL</languageCode>
        <version>1</version>
        <offerId>10</offerId>
        <rewardId>1234</rewardId>
    </args>
</request>

теперь применить XSD

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="request">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="xs:string" name="url"/>
        <xs:element type="xs:string" name="base-url"/>
        <xs:element name="args" maxOccurs="unbounded" minOccurs="0">
          <xs:complexType mixed="true">
            <xs:sequence>
              <xs:element type="xs:string" name="languageCode" minOccurs="0"/>
              <xs:element type="xs:string" name="version" minOccurs="0"/>
              <xs:element type="xs:string" name="offerId" minOccurs="1"/>
              <xs:element type="xs:string" name="rewardId" minOccurs="1"/>
            </xs:sequence>
            <xs:attribute type="xs:string" name="src" use="optional"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>