Use of the schema-element node test in XSD 1.1's assert test - xsd

I am trying to design a XML schema where a certain element may alternatively hold either a single element belonging to a substitution group or a collection of certain elements which I want to be free-order (like in "all").
Due to the limitations on the "all" type of groups I cannot nest it into a "choice", so I tried a design which is similar to the following:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" elementFormDefault="qualified" attributeFormDefault="unqualified" vc:minVersion="1.1">
<xs:element name="X" abstract="true"/>
<xs:element name="X1" substitutionGroup="X"/>
<xs:element name="X2" substitutionGroup="X"/>
<xs:element name="Y">
<xs:complexType>
<xs:all>
<xs:element ref="X" minOccurs="0"/>
<xs:element name="Z1" minOccurs="0" type="xs:string"/>
<xs:element name="Z2" minOccurs="0" type="xs:string"/>
<xs:element name="Z3" minOccurs="0" type="xs:string"/>
</xs:all>
<xs:assert test="not(schema-element(X)) or not(Z1 or Z2 or Z3)"/>
</xs:complexType>
</xs:element>
</xs:schema>
When the schema file is validated, I get the following error:
File C:\whereabouts\xsd-assertion-problem.xsd is not valid.
Assertion 'not(schema-element(X)) or not(Z)' is no valid XPath 2.0 expression.
Error location: xs:schema / xs:element / xs:complexType / xs:assert
Details
XPST0008: Element name not found in static context's in-scope element declarations
as-props-correct.2: Assertion 'not(schema-element(X)) or not(Z)' is no valid XPath 2.0 expression.
The question is: what is wrong here and how to fix it? When I read (https://www.w3.org/TR/xpath-31/#ERRXPST0008)[the description of XPath error condition], it explicitly excludes "an ElementName in an ElementTest", which should be the case here, so static analysis should not fail here. Or am I wrong?
Note that the substitution group for X is open for extension and finding all locations where references to X are made may be difficult, that's why I strongly prefer to use a schema-element-based test.
On the other hand, while writing Z1 or Z2 or Z3 is also cumbersome, these elements are local, so this solution is more or less acceptable. Of course, if there are better ideas, they are welcome!
Just in case, I rely on the Altova engine.

Related

xs:assert always fails with xerces validation, but works in xmlspy

I'm setting up Schema for our xml input/output, and have run into an issue where XMLSpy validates ok, but Xerces fails on one of the xs:asserts.
I'm using the latest xerces, xerces-2_12_0-xml-schema-1.1.
I have included all the .jar files from that distribution (except the xercesSamples.jar)
The test code is:
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/XML/XMLSchema/v1.1");
factory.setFeature("http://apache.org/xml/features/validation/cta-full-xpath-checking", true);
Schema schema = factory.newSchema(new File("C:/Imports/Test.xsd"));
validator = schema.newValidator();
validator.validate(new StreamSource("C:/Imports/Test.xml"));
I've trimmed the xsd file down to this:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:lit="http://www.w3schools.com" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" targetNamespace="http://www.w3schools.com" elementFormDefault="qualified" attributeFormDefault="unqualified" vc:minVersion="1.1">
<xs:element name="MetrixXML">
<xs:complexType>
<xs:all>
<xs:element ref="lit:Page" minOccurs="1" maxOccurs="unbounded"/>
</xs:all>
<xs:attribute name="SchemaVersion" type="xs:float" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="Page">
<xs:complexType>
<xs:attribute name="ContentPositionRule" type="xs:string"/>
<xs:attribute name="FilePageNum" type="xs:nonNegativeInteger"/>
<xs:assert test="(//#SchemaVersion ge 2.1) or ((//#SchemaVersion lt 2.1) and not (#ContentPositionRule))"/>
</xs:complexType>
</xs:element>
</xs:schema>
The xml is:
<?xml version="1.0" encoding="UTF-8"?>
<MetrixXML xmlns="http://www.w3schools.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3schools.com Test.xsd" SchemaVersion="2.1" >
<Page FilePageNum="1"/>
<Page ContentPositionRule="CenterEachPage"/>
</MetrixXML>
The error I get is:
org.xml.sax.SAXParseException: cvc-assertion: Assertion evaluation ('(//#SchemaVersion ge 2.1) or ((//#SchemaVersion lt 2.1) and not (#ContentPositionRule))') for element 'Page' on schema type '#AnonType_Page' did not succeed.
In XMLSpy, if I set SchemaVersion to 2.0, the assert fails. If I set it to 2.1, the assert succeeds.
Is there some Feature flag that I need to set?
Update:
Apparently XMLSpy is allowing things it shouldn't allow.
So, the desired test is that
if (SchemaVersion < 2.1) AND any element contains a "ContentPositionRule" attribute THEN it should fail.
Move the assertion up a level in the hierarchy and ensure that it references only descendents of the associated element:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:lit="http://www.w3schools.com"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
targetNamespace="http://www.w3schools.com"
elementFormDefault="qualified"
attributeFormDefault="unqualified" vc:minVersion="1.1">
<xs:element name="MetrixXML">
<xs:complexType>
<xs:all>
<xs:element ref="lit:Page" minOccurs="1" maxOccurs="unbounded"/>
</xs:all>
<xs:attribute name="SchemaVersion" type="xs:float" use="required"/>
<xs:assert test=" (#SchemaVersion ge 2.1) or
((#SchemaVersion lt 2.1) and
not (lit:Page/#ContentPositionRule))
</xs:complexType>
</xs:element>
<xs:element name="Page">
<xs:complexType>
<xs:attribute name="ContentPositionRule" type="xs:string"/>
<xs:attribute name="FilePageNum" type="xs:nonNegativeInteger"/>
</xs:complexType>
</xs:element>
</xs:schema>
An assertion is only allowed to reference the element on which it appears and that element's descendents – not its ancestors, siblings, etc.
See also:
How to access parent element in XSD assertion XPath?
XMLSpy's observed behavior
Although it's technically (albeit unhelpfully) conformant to provide no diagnostic assistance for assertions over siblings or ancestors of the element on which an assertion appears, XMLSpy should not be reporting differing validation results depending upon sibling or ancestor state.
W3C XML Schema Definition Language (XSD) 1.1 Part 1: Structures
Validation Rule: Assertion Satisfied
[...]
1.3 From the "partial" ·post-schema-validation infoset·, a data model instance is constructed as described in [XDM]. The root node of the
[XDM] instance is constructed from E; the data model instance contains
only that node and nodes constructed from the [attributes],
[children], and descendants of E. Note: It is a consequence of this
construction that attempts to refer, in an assertion, to the siblings
or ancestors of E, or to any part of the input document outside of E
itself, will be unsuccessful. Such attempted references are not in
themselves errors, but the data model instance used to evaluate them
does not include any representation of any parts of the document
outside of E, so they cannot be referred to.
Note: It is a consequence of this construction that attempts to refer, in an assertion, to the siblings or ancestors of E, or to any
part of the input document outside of E itself, will be unsuccessful.
Such attempted references are not in themselves errors, but the data
model instance used to evaluate them does not include any
representation of any parts of the document outside of E, so they
cannot be referred to.
[Emphasis added.]

How can I define an XML schema element that allows either base64 content or an xop:Include element?

I have a XML schema that defines an element that may be either base64 text or an xop:Include element. Currently, this is defined as a base64Binary type:
<xs:element name="PackageBinary" type="xs:base64Binary" minOccurs="1" maxOccurs="1"/>
When I insert the xop:Include element instead, it looks like this:
<PackageBinary>
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="http://google.com/data.bin" />
</PackageBinary>
But this gives an XML validation error (I'm using .NET validator):
The element 'mds:xml-schema:soap11:PackageBinary' cannot contain child
element 'http://www.w3.org/2004/08/xop/include:Include' because the
parent element's content model is text only.
This makes sense because it's not base64 content, but I thought this was common practice...? Is there any way to support this in the schema? (We have existing product that supports this syntax but we are adding validation now.)
The best I could come up with was to create a complex type that allowed any tags but was also tagged as "mixed" so it allowed text. This doesn't explicitly declare the content as base64, but it does let it pass validation.
<xs:complexType name="PackageBinaryInner" mixed="true">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
<xs:element name="PackageBinary" type="PackageBinaryInner" minOccurs="1" maxOccurs="1"/>
The solution I've found is like this:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://example.org"
elementFormDefault="qualified"
xmlns="http://example.org"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xop="http://www.w3.org/2004/08/xop/include">
<xs:import namespace="http://www.w3.org/2004/08/xop/include"
schemaLocation="http://www.w3.org/2004/08/xop/include"/>
<xs:complexType name="PackageBinary" mixed="true">
<xs:all>
<xs:element ref="xop:Include"/>
</xs:all>
</xs:complexType>
I saw this in an xml document that appeared to allow validation - basically the attribute xmlns:xop="..." did the trick:
<SomeElement xmlns:xop="http://www.w3.org/2004/08/xop/include/" id="465390" type="html">
<SomeElementSummaryURL>https://file.someurl.com/SomeImage.html</SomeElementSummaryURL>
<xop:Include href="cid:1111111#someurl.com"/>
</SomeElement >

Generate Nested Types instead of Global Types with xsd.exe

Using xsd.exe in a C# class, is there a way to produce a xsd file with Nested Type, instead of Global Types?
I want to use this xsd file, with SSIS - Sql Server Integration Services, and look SSIS is not reading my xsd very well.
I want to generate the xsd like this, with Nested Types :
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema.xsd" xmlns:mstns="http://tempuri.org/XMLSchema.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Country">
<xs:complexType>
<xs:sequence>
<xs:element name="City">
<xs:complexType>
<xs:sequence>
<xs:element name="CityName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="CoutryName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
but xsd.exe produce this , with Global Types, and SSIS don't read it. I need to change this xsd manually to be like above.
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema.xsd" xmlns:mstns="http://tempuri.org/XMLSchema.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Country">
<xs:complexType>
<xs:sequence>
<xs:element name="City" type="City">
</xs:element>
<xs:element name="CoutryName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="City">
<xs:sequence>
<xs:element name="CityName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>
Any suggestion? Or other tool that I can use.
Thanks a lot.
I'll further assume that not "very well" means you're not seeing CountryName in your XML Source output.
The documentation on MSDN is a good reading, although in my opinion it fails to describe why you would encounter the behavior you see.
I believe that it has to do with the way XML Source outputs are being determined. SSIS infers a data set from the XML structure; the top level entity, that corresponds to the root element, is not mapped to an output, so all the attributes associated with it, in your case CountryName, will not show up.
The easiest way to prove it, is to add another root element that wraps your Country (equivalent to having a dummy "root" class that has a Country-type property).
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element ref="Country"/>
</xs:sequence>
</xs:complexType>
</xs:element>
If you add the above schema fragment to your schema, you should get your expected results. At the beginning I thought that it has to do with the issue described here; while you can still use the tool to visualize the data set as described by the MSDN link above, in your case, the authoring style you suggested (basically a russian-doll) can't change the outcome.

XSD. Different between xsd:element and xs:element?

I reading articles about XSD on w3schools and here many examples. For example this:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element name="to" type="xs:string"/>
<xs:element name="from" type="xs:string"/>
<xs:element name="heading" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
But after I tried put this .xsd file in xjc - I see error log, dome like this:
The prefix "xs" for element "xs:schema" is not bound...
But all work correct when I change xs on xsd prefix.
So, can somebody, clarify for me what is different between xs and xsd?
Maybe, one prefix - it is old version and other for new version...
xs and xsd are XML prefixes used with qualified names; each prefix must be associated with a namespace. The association is done with an attribute that looks like xmlns:xs="...". xs and xsd are most common for XML Schema documents.
Should you choose s or ns1, it shouldn't make any difference to any tool for your scenario.
The error is not caused by your XML Schema file. I suspect there might be something else in your setup, maybe a custom binding file. Please check that or post additional information.

What is wrong with extending an XML Schema type using xs:all?

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="http://tempuri.org/ServiceDescription.xsd" xmlns:mstns="http://tempuri.org/ServiceDescription.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://tempuri.org/ServiceDescription.xsd" elementFormDefault="qualified" id="ServiceDescription">
<xs:element name="Template">
<xs:complexType>
<xs:complexContent>
<xs:extension base="ServiceType">
<xs:all>
<xs:element name="TemplateCode" type="xs:string"/>
</xs:all>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:complexType name="ServiceType">
<xs:all>
<xs:element name="ServiceCode" type="xs:string"/>
</xs:all>
</xs:complexType>
</xs:schema>
When I try to save this in XMLSpy it tells me
An 'all' model group is neither allowed in complex type definition 'mstns:ServiceType' nor in its extension '{anonymous}'.
Clicking Details gives a link to a paragraph in XML Schema specification which I do not understand.
Added: Ah, yes, forgot to mention - the line of error is this one:
<xs:element name="TemplateCode" type="xs:string"/>
The problem is you can't have all if you're extending another type. As far as XML knows the parent type might have a sequence model and since XML forbids putting an all group inside of a sequence group (since that would destroy the sequence group's ordering) then XML also forbids putting an all group in an extension of a complex type. You could use sequence instead of all for both though and you'd be fine.

Resources