How to reference an attribute in xsd

梦想的初衷 提交于 2020-01-15 05:43:07

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!