-->

Enforce further constraints on xsd:any?

2019-07-22 14:41发布

问题:

I have an XSD 1.0 sequence that defines a set of elements, some of which may be optional but none of which can occur more than once, and which also ends with an <xsd:any minOccurs="0" maxOccurs="unbounded" namespace="##any" processContents="lax"/> tag in order to enable users to add their own data elements in the easiest possible way when programmatically exporting conforming XML (i.e. ideally without requiring them to define their own namespace/XSD).

When processing XML that users generate, I will ignore any custom elements that they add via the <any> tag, but I want to to know if there is a way to enforce uniqueness of element names so that I can be sure that they're not putting in duplicates of elements defined in the sequence with maxOccurs=1?

Here is a sample xsd (interactive version here):

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns="testxsd" targetNamespace="testxsd" 
            xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
            elementFormDefault="qualified">
    <xsd:element name="XSDSequence">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="itemA" type="xsd:string"
                             minOccurs="1" maxOccurs="1"/>
                <xsd:element name="itemB" type="xsd:string"
                             minOccurs="0" maxOccurs="1"/>
                <xsd:element name="itemC" type="xsd:string"
                             minOccurs="1" maxOccurs="1"/>
                <xsd:any minOccurs="0" maxOccurs="unbounded" 
                         namespace="##any" processContents="lax"/>  
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

and here is a sample XML that passes XSD validation but which I would like to error out on due to the duplicated <itemA> at the end:

<XSDSequence xmlns="testxsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <itemA>foo</itemA>
    <itemC>bar</itemC>
    <randomElement>this is ok</randomElement>
    <itemA>I want this second itemA to cause an error</itemA>
</XSDSequence>

(Note that capturing data items via attributes rather than elements is not something that I want to do.)

回答1:

No, in XSD 1.0, once you've allowed any element, you can't specify further constraints beyond those afforded by minOccurs, maxOccurs, namespace, and processContents.

In XSD 1.1, you can also make xsd:assertions against the xsd:any elements; you'd be able to express your constraint with an assertion. [Update: Don't miss @C. M. Sperberg-McQueen's simpler idea for XSD 1.1: xsd:any/@notQName="itemA itemB itemC"]



回答2:

Perhaps the simplest way to ensure that the elements itemA, itemB, and itemC are not repeated is to use namespace="##other" instead of namespace="##any". (This assumes that elements in the namespace testxsd other than those three will not need to appear here.)

Or move to XSD 1.1 and add the attribute notQName="itemA itemB itemC".