Правильный способ использования ключа в xsd - PullRequest
3 голосов
/ 09 октября 2009

Я пишу схему XSD для проекта, над которым я работаю. Схема ниже - та, которую я взял из примера Microsoft и немного изменил.

Я пытаюсь использовать ключ и keyref, чтобы объявить уникальный ключ для одного набора элементов, а затем обратиться к этому ключу в другом разделе.

Я не мог заставить его работать долгое время. Я бы написал схему и настроил тестовый документ, который не прошел валидацию из-за (1) дубликатов ключей и (2) ссылок, ссылающихся на несуществующие ключи, но он продолжал проходить.

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

Я проверяю, используя .NET XmlDocument и XmlSchema. Я вставлю код проверки теста внизу.

Мой вопрос: почему ключ работает, если он объявлен так, как показано ниже, но не работает, если он объявлен так, как он есть в комментарии?

XSD:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
      targetNamespace="namespace1"
      xmlns="namespace1"
      xmlns:r="namespace1"
      elementFormDefault="qualified">  

<xs:element name="root">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="A" type="r:AType" maxOccurs="unbounded">
        <xs:keyref name="dummy" refer="r:pNumKey">
          <xs:selector xpath="part"/>
          <xs:field xpath="@ref-number"/>
        </xs:keyref>
      </xs:element>
      <xs:element name="B" type="r:BType"/>
    </xs:sequence>
  </xs:complexType>

  <!-- This works. -->
  <xs:key name="pNumKey">
    <xs:selector xpath="r:B/r:part"/>
    <xs:field xpath="@key-number"/>
  </xs:key>
  <!--
  This doesn't work.

  <xs:key name="pNumKey">
    <xs:selector xpath="B/part"/>
    <xs:field xpath="@key-number"/>
  </xs:key>
  -->
</xs:element>

<xs:complexType name="AType">
  <xs:sequence>
    <xs:element name="part" maxOccurs="unbounded">
      <xs:complexType>
        <xs:simpleContent>
          <xs:extension base="xs:string">
            <xs:attribute name="ref-number" type="xs:integer"/>
          </xs:extension>
        </xs:simpleContent>
      </xs:complexType>
    </xs:element>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="BType">
  <xs:sequence>
    <xs:element name="part" maxOccurs="unbounded">
      <xs:complexType>
        <xs:attribute name="key-number" type="xs:integer"/>
      </xs:complexType>
    </xs:element>
  </xs:sequence>
</xs:complexType>
</xs:schema>

код проверки:

    private static void ValidateXml(string root, string xsdFileName, string xmlFileName)
    {
        ValidationEventHandler veh = new ValidationEventHandler(Program_ValidationEventHandler);
        XmlSchema schema = XmlSchema.Read(new XmlTextReader(root + xsdFileName), veh);

        XmlDocument xdoc = new XmlDocument();
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.Schemas.Add(schema);

        settings.ValidationType = ValidationType.Schema;

        settings.ValidationEventHandler +=
            new ValidationEventHandler(Program_ValidationEventHandler);

        XmlReader reader = XmlReader.Create(root + xmlFileName, settings);

        xdoc.Load(reader);

        Console.WriteLine(xdoc.SchemaInfo.Validity);
    }

    private static void Program_ValidationEventHandler(object sender, ValidationEventArgs e)
    {
        Console.WriteLine(string.Format("-Message:{0}", e.Message));
    }

1 Ответ

7 голосов
/ 10 октября 2009

Я не уверен на 100%, но мое довольно уверенное предположение состоит в том, что выражение XPath в элементе selector не заботится о целевом пространстве имен, только о пространствах имен, которые вы объявили с атрибутами xmlns. Таким образом, поскольку вы не объявили пространство имен по умолчанию, оно пытается обеспечить уникальность элементов part в пространстве имен. А поскольку элементы part в вашем документе, кажется, находятся в пространстве имен namespace1, у вас нет элементов part в пространстве имен, поэтому это ограничение уникальности успешно выполняется.

Вы можете проверить мои предположения, добавив к элементу schema атрибут xmlns="namespace1". (Поскольку все ваши элементы в документе схемы имеют префиксы, это единственное, что вам нужно сделать.) Если ваш закомментированный элемент key сработает тогда, это будет правильным объяснением.

РЕДАКТИРОВАТЬ: Хорошо, я нашел ответ. Оказывается, что в XPath 1.0, когда у вас есть имя без префикса, оно автоматически интерпретируется как отсутствие пространства имен. Невозможно установить пространство имен по умолчанию в XPath 1.0, поэтому вам всегда нужно ставить префикс перед всеми именами в выражениях XPath, когда они находятся в некотором пространстве имен. Поэтому независимо от того, объявили ли вы пространство имен по умолчанию в документе схемы, закомментированное определение key пытается сопоставить имена без пространства имен, что не соответствует вашему документу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...