Как использовать keyref для тега вложенного элемента - PullRequest
0 голосов
/ 02 мая 2020

Что я хочу проверить:

<root xsi:noNamespaceSchemaLocation="test.xsd" xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
    <A>
      <a id="ID-1"/>
      <a id="ID-2"/>
    </A>
    <BBB>
      <b>
        <bb>
            <bbb idref="ID-1"></bbb>
        </bb>
      </b>
    </BBB>
</root>

Вот мой .xsd файл:

  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" >

  <xsd:element name="root">
    <xsd:complexType>
      <xsd:all minOccurs="1" maxOccurs="1">
        <xsd:element name="A" type="myA"/>
        <xsd:element name="BBB" type="myBBB"/>
      </xsd:all>
    </xsd:complexType>
    <xsd:key name="myId">
      <xsd:selector xpath="./A/a"/>
      <xsd:field xpath="@id"/>
    </xsd:key>

    <xsd:keyref name="myIdref" refer="myId">
      <xsd:selector xpath="./BBB/b/bb/bbb"/>
      <xsd:field xpath="@idref"/>
    </xsd:keyref>
  </xsd:element>

  <xsd:complexType name="myA">
    <xsd:sequence minOccurs="1">
      <xsd:element name="a">
        <xsd:complexType>
          <xsd:attribute name="id" type="xsd:ID"/>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>

  <xsd:complexType name="myBBB">
    <xsd:sequence minOccurs="1">
      <xsd:element name="b">
        <xsd:complexType>
          <xsd:all>
              <xsd:element name="bb">
                  <xsd:complexType>
                      <xsd:sequence>
                          <xsd:element name="bbb">
                              <xsd:complexType>
                                  <xsd:simpleContent>
                                      <xsd:extension base="xsd:string">
                                          <xsd:attribute name="idref" type="xsd:ID"></xsd:attribute>
                                      </xsd:extension>
                                  </xsd:simpleContent>
                              </xsd:complexType>
                          </xsd:element>
                      </xsd:sequence>
                  </xsd:complexType>
              </xsd:element>
          </xsd:all>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

Однако я получаю:

элемент bbb: ошибка достоверности схемы: элемент 'bbb', атрибут 'idref':
Предупреждение: нет предварительно рассчитанного значения, значение либо недопустимо, либо произошло что-то странное.

Я пытался использовать xsd:NCName но это ничего не изменило. Если я использую ID-3, который еще не определен, я получаю

Не найдено совпадений для последовательности ключей ['ID-3'] из keyref 'myIdref'.

Я хочу сослаться на id элемента A с idref элемента bbb. Мой xPath не так?
Разве я не должен использовать xsd:ID для keyRef?

Ответы [ 2 ]

1 голос
/ 03 мая 2020

Вы видите довольно плохую диагностику от вашего процессора схемы: какое программное обеспечение выводит сообщение об ошибке типа "или что-то странное произошло"?

Вот вывод из Saxon:

Processing file:/Users/mike/Desktop/temp/test.xml
Validation error on line 4 column 19 of test.xml:
  FORG0001: In content of element <A>: The content model does not allow element <Q{}a> to
  appear more than once. 
  See http://www.w3.org/TR/xmlschema-1/#cvc-complex-type clause 2.4
Validation error on line 4 column 19 of test.xml:
  The field in constraint {myId} has no value
  See http://www.w3.org/TR/xmlschema-1/#cvc-identity-constraint clause 4.2.1
Validation error on line 9 column 27 of test.xml:
  XQDY0027: ID value 'ID-1' is not unique
  See http://www.w3.org/TR/xmlschema-1/#cvc-id clause 2

Давайте go через эти.

Первый легко исправить, добавив maxOccurs = "unbounded" в типе myA.

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

Третья ошибка - потому что вы объявили bbb/@idref как xs: ID. Если вы измените его на xs: NCName, ошибка исчезнет.

Вам необходимо решить, хотите ли вы выполнить проверку ссылочной целостности, используя механизм ID / IDREF или механизм key / keyref. Нет смысла использовать оба.

1 голос
/ 03 мая 2020

Полагаю, ваша проблема в том, что вы хотите, чтобы тип атрибута элемента bbb был xsd:IDREF, а не xsd:ID. Тогда это будет соответствовать вашему xsd:ID определению:

<xsd:attribute name="idref" type="xsd:IDREF"></xsd:attribute>

Незначительное исправление, которое нужно добавить, это добавление атрибута maxOccurs="unbounded" к

...
<xsd:complexType name="myA">
    <xsd:sequence minOccurs="1" maxOccurs="unbounded">
    ...

Таким образом, весь XSD может be

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" >

  <xsd:element name="root">
    <xsd:complexType>
      <xsd:all minOccurs="1" maxOccurs="1">
        <xsd:element name="A" type="myA"/>
        <xsd:element name="BBB" type="myBBB"/>
      </xsd:all>
    </xsd:complexType>
    <xsd:key name="myId">
      <xsd:selector xpath="./A/a"/>
      <xsd:field xpath="@id"/>
    </xsd:key>

    <xsd:keyref name="myIdref" refer="myId">
      <xsd:selector xpath="./BBB/b/bb/bbb"/>
      <xsd:field xpath="@idref"/>
    </xsd:keyref>
  </xsd:element>

  <xsd:complexType name="myA">
    <xsd:sequence minOccurs="1" maxOccurs="unbounded">
      <xsd:element name="a">
        <xsd:complexType>
          <xsd:attribute name="id" type="xsd:ID"/>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>

  <xsd:complexType name="myBBB">
    <xsd:sequence minOccurs="1">
      <xsd:element name="b">
        <xsd:complexType>
          <xsd:all>
              <xsd:element name="bb">
                  <xsd:complexType>
                      <xsd:sequence>
                          <xsd:element name="bbb">
                              <xsd:complexType>
                                  <xsd:simpleContent>
                                      <xsd:extension base="xsd:string">
                                          <xsd:attribute name="idref" type="xsd:IDREF"></xsd:attribute>
                                      </xsd:extension>
                                  </xsd:simpleContent>
                              </xsd:complexType>
                          </xsd:element>
                      </xsd:sequence>
                  </xsd:complexType>
              </xsd:element>
          </xsd:all>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

Теперь ваш XSD должен проверить ваш XML.
Чтобы сделать эту работу, вам даже не нужен

<xsd:key name="myId">
  <xsd:selector xpath="./A/a"/>
  <xsd:field xpath="@id"/>
</xsd:key>

<xsd:keyref name="myIdref" refer="myId">
  <xsd:selector xpath="./BBB/b/bb/bbb"/>
  <xsd:field xpath="@idref"/>
</xsd:keyref>

, потому что эта функциональность подразумевается в код xsd:ID / xsd:IDREF. xs:keyref более гибкий, но в вашем примере он не нужен.

...