Как ссылаться на атрибут в xsd
Я попытался определить атрибут, на который можно ссылаться в последующих определениях элементов.
<xs:attribute name="ridref" type="xs:string"/>
Позже я использую это так:
<xs:element name="coordRegRef">
<xs:complexType>
<!--xs:attribute name="ridref" type="xs:string"/ this works but I want to use ref -->
<xs:attribute ref="ridref" use="required"/>
</xs:complexType>
</xs:element>
XSD прекрасно компилируется с xmllint
xmllint --schema pc-ar.xsd pc-ar.xml
Но xmllint говорит
pc-ar.xml:41: element coordRegRef: Schemas validity error : Element '{http://pc-ar.xsd}coordRegRef', attribute 'ridref': The attribute 'ridref' is not allowed.
pc-ar.xml:41: element coordRegRef: Schemas validity error : Element '{http://pc-ar.xsd}coordRegRef': The attribute '{http://pc-ar.xsd}ridref' is required but missing.
который я интерпретирую как означающий, что мой XML-файл должен использовать пространство имен для ridref
<coordRegRef fix:ridref="111"/>
(который работает, но нежелательно) вместо
<coordRegRef ridref="111"/>
Зачем?
Мой XSD
<?xml version="1.0"?>
<!-- validate: xmllint - -schema pc-ar.xsd pc-ar.xml -->
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://pc-ar.xsd"
elementFormDefault="qualified"
xmlns="http://pc-ar.xsd"
xmlns:fix="http://pc-ar.xsd">
<!--xs:attribute name="rid" type="xs:integer"/-->
<!--xs:attributeGroup name="ridGroup">
<xs:attribute name="rid" type="xs:integer">
<xs:annotation>
<xs:documentation>entry id</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup-->
<xs:element name="name" type="xs:string"/>
<xs:attribute name="id" type="xs:ID"/>
<xs:attribute name="idref" type="xs:IDREF"/>
<xs:attribute name="ridref" type="xs:string"/>
<xs:element name="coordRegRef">
<xs:complexType>
<!--xs:attribute name="ridref" type="xs:string"/works-->
<xs:attribute ref="ridref" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="assetRegRef">
<xs:complexType>
<xs:sequence>
<xs:element name="ridref2" type="xs:string"/>
</xs:sequence>
<!--xs:attribute name="ridref" type="xs:string"/works-->
<xs:attribute name="ridref" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="lat">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:minInclusive value="-40"/>
<xs:maxInclusive value="-30"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="lon" type="xs:decimal"/>
<xs:complexType name="coordRegTableType">
<xs:sequence>
<xs:element name="entry" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element ref="name"/>
<xs:element ref="lat"/>
<xs:element ref="lon"/>
</xs:sequence>
<xs:attribute name="rid" type="xs:string"/>
<!--xs:attribute ref="fix:id" use="required"/-->
<xs:attribute name="id" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="assetRegTableType">
<xs:sequence>
<xs:element name="entry" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element ref="name"/>
<xs:element ref="coordRegRef"/>
<xs:element ref="assetRegRef"/>
</xs:sequence>
<xs:attribute name="rid" type="xs:string"/>
<xs:attribute name="id" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:element name="coordReg" type="fix:coordRegTableType">
<xs:unique name="coordRegNameUniq">
<xs:selector xpath="*"/>
<xs:field xpath="fix:name"/>
</xs:unique>
</xs:element>
<xs:element name="assetReg" type="assetRegTableType">
<xs:unique name="assetRegNameUniq">
<xs:selector xpath="fix:entry"/>
<xs:field xpath="fix:name"/>
</xs:unique>
</xs:element>
<xs:element name="assetExchange">
<xs:complexType>
<xs:sequence>
<xs:element ref="coordReg"/>
<xs:element ref="assetReg"/>
</xs:sequence>
<xs:attribute name="rid" type="xs:integer"/>
<!--xs:attribute ref="id" use="required"/-->
</xs:complexType>
<xs:key name="coordRegKey">
<xs:selector xpath="fix:coordReg/fix:entry"/>
<xs:field xpath="@rid"/>
</xs:key>
<xs:key name="assetRegKey">
<xs:selector xpath="fix:assetReg/fix:entry"/>
<xs:field xpath="@rid"/>
</xs:key>
<xs:keyref name="assetRegKeyRef" refer="assetRegKey">
<xs:selector xpath=".//fix:assetRegRef"/>
<xs:field xpath="@ridref"/>
</xs:keyref>
<xs:keyref name="assetRegKeyRef2" refer="assetRegKey">
<!--xs:selector xpath=".//fix:assetRegRef"/works-->
<!--xs:selector xpath="./*/*/fix:assetRegRef"/works-->
<!--xs:selector xpath="./*/fix:entry/fix:assetRegRef"/works-->
<!--xs:selector xpath="./*/*/fix:assetRegRef"/works-->
<xs:selector xpath=".//fix:assetRegRef"/> <!-- any assetRefRef -->
<xs:field xpath="fix:ridref2"/>
</xs:keyref>
<xs:keyref name="coordRegKeyRef" refer="coordRegKey">
<xs:selector xpath=".//fix:coordRegRef"/>
<xs:field xpath="@ridref"/>
</xs:keyref>
</xs:element>
</xs:schema>
Мой тестовый файл XML
<?xml version="1.0"?>
<assetExchange
xmlns="http://pc-ar.xsd"
xmlns:fix="http://pc-ar.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pc-ar.xsd pc-ar.xsd"
rid="1">
<coordReg>
<entry id="1" rid="111">
<name>sitea</name>
<lat>-31.23</lat>
<lon>151</lon>
</entry>
<entry id="2" rid="222">
<name>siteb</name>
<lat>-31.23</lat>
<lon>151</lon>
</entry>
<entry id="3" rid="333">
<name>sitec</name>
<lat>-31.23</lat>
<lon>151</lon>
</entry>
</coordReg>
<assetReg>
<entry id="11" rid="11">
<name>deva</name>
<coordRegRef fix:ridref="111"/>
<assetRegRef ridref="aa"><ridref2>aa</ridref2></assetRegRef>
</entry>
<entry id="22" rid="22">
<name>devb</name>
<coordRegRef ridref="2212"/>
<assetRegRef ridref="11"><ridref2>11</ridref2></assetRegRef>
</entry>
<entry id="33" rid="33">
<name>devc</name>
<coordRegRef ridref="333"/>
<assetRegRef ridref="44"><ridref2>44</ridref2></assetRegRef>
</entry>
</assetReg>
</assetExchange>
2 ответа
Как вы заметили, и как видно из ошибки валидации, парсер действительно ожидает атрибут ridref
но это должно быть в пространстве имен.
Причина этого заключается в том, что в XML-схемах все глобальные определения элементов, атрибутов или типов должны быть квалифицированы. Это приводит к тому, что все ваши глобально определенные атрибуты будут иметь префикс пространства имен, даже если вы установили attributeFormDefault="unqualified"
, Обходной путь должен определить такие атрибуты внутри <xs:attributeGroup>
(или в глобальном типе). В этом случае имя группы атрибутов получает присоединенное к ней пространство имен вместо имени атрибута внутри нее. Тогда вы можете использовать ref
ссылаться на эти группы атрибутов и получать ваши глобально используемые атрибуты, не помещая их в пространство имен.
Поскольку вы объявляете глобальные атрибуты, они являются частью {http://pc-ar.xsd}
Пространство имен. А атрибуты без префиксов в XML всегда принадлежат пространству без имен. Поэтому, если вы не хотите объявлять атрибуты локально, а также не хотите добавлять префиксы к атрибутам в вашем XML, альтернативой является их обертывание внутри групп атрибутов:
<xs:attributeGroup name="required-ridref">
<xs:attribute name="ridref" type="xs:string" use="required"/>
</xs:attributeGroup>
<xs:attributeGroup name="not-required-ridref">
<xs:attribute name="ridref" type="xs:string" use="required"/>
</xs:attributeGroup>
И укажите группу, в которой вы бы указали атрибут:
<xs:element name="coordRegRef">
<xs:complexType>
<xs:attributeGroup ref="required-ridref" />
</xs:complexType>
</xs:element>
<xs:element name="assetRegRef">
<xs:complexType>
<xs:sequence>
<xs:element name="ridref2" type="xs:string"/>
</xs:sequence>
<xs:attributeGroup ref="not-required-ridref"/>
</xs:complexType>
</xs:element>