问题
I tried to define an attribute that could be referenced in subsequent element definitions.
<xs:attribute name="ridref" type="xs:string"/>
Later I use it like this:
<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 compiles fine with xmllint
xmllint --schema pc-ar.xsd pc-ar.xml
But xmllint says
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.
which I interpret as meaning that my XML file must use a namespace for ridref
<coordRegRef fix:ridref="111"/>
(which does work, but undesired) instead of
<coordRegRef ridref="111"/>
Why?
My 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>
My XML test file
<?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>
回答1:
As you noticed, and as it can be seen from the validation error, the parser does expect the attribute ridref
but it must be in a namespace.
The reason for that is that in XML Schemas all global element, attribute or type definitions must be qualified. This has the consequence that all your globally defined attributes will be namespace prefixed even if you have set attributeFormDefault="unqualified"
. A workaround is to define such attributes alone inside <xs:attributeGroup>
(or in a global type). In that case the name of the attribute group gets the namespace attached to it instead of the name of the attribute inside it. Then you can use ref
to refer to those attribute groups and get your globally usable attributes without having them to be in a namespace.
回答2:
Since you are declaring global attributes, they are part of the {http://pc-ar.xsd}
namespace. And unprefixed attributes in XML always belong to no-namespace. So if you don't want to declare the attributes locally, and also don't want to prefix the attributes in your XML, an alternative is to wrap them inside atrribute groups:
<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>
And reference the group where you would reference the attribute:
<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>
来源:https://stackoverflow.com/questions/23025859/how-to-reference-an-attribute-in-xsd