简体   繁体   中英

XSD - Define “abstract” base element type with multiple “concrete” sub element types

My goal is to have an XML that defines a filter on messages. The root <Filter> element will have zero or more "FilterRule"s which can be one of an <Include> or <Exclude> rule elements.

Both <Include> and <Exclude> are identical elements, and differ only by their name.
I would like to define a "base" type called "FilterRule". This type will be "abstract" and cannot be used in the actual XML.
Then, I want to define two "concrete" types: "Include" and "Exclude", that would inherit from the base type.

Each "FilterRule" can in turn contain zero or more sub "FilterRule"s.

Two example usages:

<?xml version="1.0" encoding="UTF-8"?>
<Filter>
  <!-- By default all the messages are included, so let's first exclude everything: -->
  <Exclude type="regex" filteredEntity="ORIGINAL_MESSAGE" value=".*">
    <!-- And now include only the *Important* messages: -->
    <Include type="regex" filteredEntity="ORIGINAL_MESSAGE" value=".*Important.*"/>
  </Exclude>
</Filter>

And

<?xml version="1.0" encoding="UTF-8"?>
<Filter>
  <!-- By default all the messages are included, lets exlcude the annoying and redundant ones: -->
  <Exclude type="regex" filteredEntity="ORIGINAL_MESSAGE" value="AnnoyingSource:.*"/>
  <Exclude type="regex" filteredEntity="ORIGINAL_MESSAGE" value=".*: Redundant Message"/>
</Filter>

I am new to XSD so I'm probably doing thing terribly wrong... this is what I have so far (this XSD does not even validates by itself):

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:complexType name="FilterRule">
    <xs:sequence>
      <xs:element name="FilterRule" maxOccurs="unbounded" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute type="filterType" name="filterType"/>
    <xs:attribute type="filteredEntity" name="filteredEntity"/>
    <xs:attribute type="xs:string" name="value" />
  </xs:complexType>

  <xs:complexType name="Exclude">
    <xs:complexContent>
      <xs:extension base="FilterRule"/>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="Include">
    <xs:complexContent>
      <xs:extension base="FilterRule"/>
    </xs:complexContent>
  </xs:complexType>

  <xs:simpleType name="filterType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="REGEX"/>
      <xs:enumeration value="EQUALS"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="filteredEntity">
    <xs:restriction base="xs:string">
      <xs:enumeration value="ORIGINAL_MESSAGE"/>
      <xs:enumeration value="PROCESSED_MESSAGE"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:element name="Filter" maxOccurs="1" minOccurs="1">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="FilterRule" maxOccurs="unbounded" minOccurs="0"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

So, what am I doing wrong?

PS the XSD will be used to generate JAXB (Java) classes.

Why are you trying to use extension element. The types for Include and Exclude are same and the same type should be used. Element names may vary.

Sample XSD:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:complexType name="FilterRuleType">
        <xs:sequence>
            <xs:element name="Exclude" type="FilterRuleType" maxOccurs="unbounded" minOccurs="0"/>
                <xs:element name="Include" type="FilterRuleType" maxOccurs="unbounded" minOccurs="0"/>
        </xs:sequence>
        <xs:attribute type="filterType" name="filterType"/>
        <xs:attribute type="filteredEntity" name="filteredEntity"/>
        <xs:attribute type="xs:string" name="value"/>
    </xs:complexType>

    <xs:simpleType name="filterType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="REGEX"/>
            <xs:enumeration value="EQUALS"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="filteredEntity">
        <xs:restriction base="xs:string">
            <xs:enumeration value="ORIGINAL_MESSAGE"/>
            <xs:enumeration value="PROCESSED_MESSAGE"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:element name="Filter">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Exclude" type="FilterRuleType" maxOccurs="unbounded" minOccurs="0"/>
                <xs:element name="Include" type="FilterRuleType" maxOccurs="unbounded" minOccurs="0"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

Here is how your schema fails with the Saxon schema processor:

Error at xs:element on line 37 column 59 of test.xsd:
  Attribute @maxOccurs is not allowed on element <xs:element>
Error at xs:element on line 37 column 59 of test.xsd:
  Attribute @minOccurs is not allowed on element <xs:element>
Schema processing failed: 2 errors were found while processing the schema

That's a very simple error (the number of times an element may appear is always defined at the point where you use the element definition, not at the point where you define it.) When you fix this, in the obvious way by removing the offending attributes, the schema validates.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM