如何在嵌套元素标签上使用keyref

时间:2020-05-02 20:52:11

标签: xml xsd xsd-validation

我要验证的内容:

<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,则会得到

找不到与keyref'myIdref'的键序列['ID-3']相匹配的内容。

我想用bbb元素的id引用A元素的idref。我的xPath错误吗?
我不应该对xsd:ID使用keyRef吗?

2 个答案:

答案 0 :(得分:1)

我想您的问题是您希望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可能是

<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更灵活,但在您的示例中,则不需要。

答案 1 :(得分:1)

您会从模式处理器中看到一些非常差的诊断信息:哪种软件会输出错误消息,例如“或发生了奇怪的事情”?

这是撒克逊人的输出:

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

我们来看看这些。

通过在类型myA中添加maxOccurs =“ unbounded”可以轻松解决第一个问题。

解决此问题时,第二个错误消失了:我认为Saxon在选择器中对XPath表达式的评估是在假设数据将是有效的,但由于此假设不成立而没有发现任何东西。

第三个错误是因为您将bbb/@idref声明为xs:ID。如果将其更改为xs:NCName,则错误消失。

您需要确定是要使用ID / IDREF机制还是通过key / keyref机制进行参照完整性检查。两者都没有意义。