XML Schema with repeating elements - c#

I am trying to deserialise the following XML:
<queries>
<query name='abc'>
<statement>SELECT * FROM table1</statement>
<label row='1' name='id'/>
<label row='2' name='name'/>
</query>
<query name='another'>
<statement>SELECT * FROM table2</statement>
<label row='1' name='myTabID'/>
<label row='2' name='myTabName'/>
</query>
</queries>
To validate the schema I am using:
<xs:complexType name="Queries">
<xs:sequence>
<xs:element name="query" type="Query"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Query">
<xs:sequence>
<xs:element name="statement" minOccurs="1" maxOccurs="1"/>
<xs:element name="label">
<xs:complexType>
<xs:attribute name="row" type="xs:int" use="required"/>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
Validation is failing with the message:
Not valid.
Error - Line 7, 48: org.xml.sax.SAXParseException; lineNumber: 7; columnNumber: 48; cvc-complex-type.2.4.d: Invalid content was found starting with element 'label'. No child element is expected at this point.
Error - Line 9, 31: org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 31; cvc-complex-type.2.4.d: Invalid content was found starting with element 'query'. No child element is expected at this point.
What am I missing please? Do I need to specify a different tag than sequence? I want to enforce at least one query existing.
Thank you in advanced :)

The error message complains about the definition
<xs:element name="label">
and the use
<label row='1' name='id'/>
<label row='2' name='name'/>
The default values (W3) for minOccurs and maxOccurs is 1, so you can only use one label there. You need to change it if you like to use more labels. Use unbounded for arbitrary amount.
Also note that similar maxOccurs adjustment (unbounded or greater than 1) is needed for query (as commented by #kjhughes)

try this :
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="queries">
<xs:complexType>
<xs:sequence>
<xs:element name="query" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="statement"/>
<xs:element name="label" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="row" use="optional"/>
<xs:attribute type="xs:string" name="name" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="name" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Related

Element http://www.w3.org/2001/XMLSchema:complexType is invalid in this context

I'm trying to validate this XML file
<session>
<mic id="1" posname="T1" x="0.0" y="0.0" z="0.0" />
</session>
using this XSD file
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
attributeFormDefault="unqualified"
elementFormDefault="qualified">
<xs:element name="session">
<xs:complexType>
<xs:sequence>
<xs:element name="mic" type="micType" minOccurs="1" maxOccurs="4">
</xs:element>
<xs:complexType name="micType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="id"/>
<xs:attribute type="xs:string" name="posname"/>
<xs:attribute type="xs:float" name="x"/>
<xs:attribute type="xs:float" name="y"/>
<xs:attribute type="xs:float" name="z"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
but I get this error message:
XmlSchema error: Element http://www.w3.org/2001/XMLSchema:complexType is invalid in this context.
If I just have the attribute definition for the mic element the program runs fine. I don't know what I'm doing wrong. I'm trying to have the XSD validate the data types for the mic element. Can anybody please tell me what I'm doing wrong?
The complexType named micType should be defined as a global type declaration, i.e. it should be an immediate child of the xs:schema element.
What you have is a non-viable hybrid of a local and global declaration of a complex type. Either define a micType globally (as Michael Kay mentioned) or locally:
Global complexType declaration
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
attributeFormDefault="unqualified"
elementFormDefault="qualified">
<xs:element name="session">
<xs:complexType>
<xs:sequence>
<xs:element name="mic" type="micType" minOccurs="1" maxOccurs="4"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="micType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="id"/>
<xs:attribute type="xs:string" name="posname"/>
<xs:attribute type="xs:float" name="x"/>
<xs:attribute type="xs:float" name="y"/>
<xs:attribute type="xs:float" name="z"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
Local complexType declaration
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
attributeFormDefault="unqualified"
elementFormDefault="qualified">
<xs:element name="session">
<xs:complexType>
<xs:sequence>
<xs:element name="mic" minOccurs="1" maxOccurs="4">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="id"/>
<xs:attribute type="xs:string" name="posname"/>
<xs:attribute type="xs:float" name="x"/>
<xs:attribute type="xs:float" name="y"/>
<xs:attribute type="xs:float" name="z"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Either way is ok and will successfully validate your XML.

XSD Use single restriction for multiple elements

I have an XML file that is produced from a customer system where decimal values are output with commas instead of decimal points so like 10,5 or 1250,50 instead of 10.5 or 1250.50.
I need to validate and deserialise this XML file so I am trying to get a XSD schema created to do the validation and once validated deserialise the file.
Everything works ok except for validating the numbers because of the comma.
I have the following restriction for the XSD but I cannot figure out how to add the restriction once and use it for multiple different elements since there can be a lot of items with numbers in them:
<xs:restriction base="xs:string">
<xs:pattern value="^\d+(\,\d{1,2})?$"/>
</xs:restriction>
I've tried to add the following block inside the InvoiceRow element in the XSD sample below but it just seems to break the XSD format:
<xs:simpleType name="DecimalValidation">
<xs:restriction base="xs:string">
<xs:pattern value="^\d+(\,\d{1,2})?$"/>
</xs:restriction>
</xs:simpleType>
This is my XSD and the places where "xs:decimal" have been set are the items that have the number values with the commas in it and I need to use the restriction to validate them.
<xs:element name="InvoiceRow" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="ArticleIdentifier"/>
<xs:element type="xs:string" name="ArticleName"/>
<xs:element name="OrderedQuantity">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:short">
<xs:attribute type="xs:string" name="QuantityUnitCode" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="UnitPriceAmount">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute type="xs:string" name="AmountCurrencyIdentifier" use="optional"/>
<xs:attribute type="xs:string" name="UnitPriceUnitCode" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element type="xs:short" name="RowVatRatePercent"/>
<xs:element name="RowVatAmount">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute type="xs:string" name="AmountCurrencyIdentifier" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="RowVatExcludedAmount">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute type="xs:string" name="AmountCurrencyIdentifier" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="RowAmount">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute type="xs:string" name="AmountCurrencyIdentifier" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
Thanks for any info or suggestions around this.
Because your simple type DecimalValidation is named, it should appear at the top level of the schema as a global declaration (that is, as a child of xs:schema), and you should then be able to replace all references to xs:decimal by references to DecimalValidation. (It looks like there are no namespaces involved, but if there are, you might need to add a suitable namespace prefix.)

Confusion over error message "invalid XPath for selector or field"

I am trying to better understand key and keyref and how to use them in a schema. I would like to apply a key to parts of type y, but not parts of type z. I am confused as to why I am seeing the following error.
'r:B/r:part[#type='y']' is an invalid XPath for selector or field
I am all but certain that the XPath is valid, but I get an error from Visual Studio as soon as I enter the predicate filter in the XPath expression.
Here is the XML
<root xmlns="namespace1">
<A>
<!-- if the ref-number is not equal to one of the key-number, the validation will give error -->
<part ref-number="1"/>
</A>
<A>
<!-- if the ref-number is not equal to one of the key-number, the validation will give error -->
<part ref-number="2"/>
</A>
<B>
<part type="y" key-number="1"/>
<part type="y" key-number="2"/>
<part type="z" key-number="3"/>
</B>
</root>
Here is the schema
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="namespace1" xmlns:r="namespace1" elementFormDefault="qualified">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="A" type="r:aType" maxOccurs="unbounded">
<xs:keyref name="dummy" refer="r:partNumberKey">
<xs:selector xpath="r:part"/>
<xs:field xpath="#ref-number"/>
</xs:keyref>
</xs:element>
<xs:element name="B" type="r:bType"/>
</xs:sequence>
</xs:complexType>
<xs:key name="partNumberKey">
<!-- I get an error here -->
<xs:selector xpath="r:B/r:part[#type='y']"/>
<xs:field xpath="#key-number"/>
</xs:key>
</xs:element>
<xs:complexType name="aType">
<xs:sequence>
<xs:element name="part" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="ref-number" type="xs:integer"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="bType">
<xs:sequence>
<xs:element name="part" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="key-number" type="xs:integer"/>
<xs:attribute name="type" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
You get a more meaningful error message from Xerces/Oxygen:
[Xerces] c-general-xpath: The expression 'r:B/r:part[#type='y']' is not valid with respect to the XPath subset supported by XML Schema.
XML Schema only supports a subset of XPath. The following rule lists the contents allowed as the value of the xpath attribute of xs:selector:
[1] Selector ::= Path ( '|' Path )*
[2] Path ::= ('.//')? Step ( '/' Step )*
[3] Step ::= '.' | NameTest
[4] NameTest ::= QName | '*' | NCName ':' '*'
Which is a cryptic way of saying that expressions with predicates (between [ and ]) are not supported in this context.
If you have designed this XML yourself, you could give distinct names to part elements instead of different type attributes.
Another approach would be to include a Schematron rule in your XML Schema that performs this check.
Modified XML Schema with embedded Schematron
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:r="namespace1"
xmlns:sch="http://purl.oclc.org/dsdl/schematron"
targetNamespace="namespace1"
elementFormDefault="qualified">
<xs:annotation>
<xs:appinfo>
<sch:ns uri="namespace1"
prefix="r" />
<sch:pattern>
<sch:rule context="r:A/r:part">
<sch:assert test="#ref-number = /r:root/r:B/r:part/#key-number">Key Error!</sch:assert>
</sch:rule>
</sch:pattern>
</xs:appinfo>
</xs:annotation>
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="A" type="r:aType" maxOccurs="unbounded"/>
<xs:element name="B" type="r:bType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="aType">
<xs:sequence>
<xs:element name="part" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="ref-number" type="xs:integer"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="bType">
<xs:sequence>
<xs:element name="part" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="key-number" type="xs:integer"/>
<xs:attribute name="type" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
I am not sure this is exactly what you want, because I did not fully understand why the type attribute of the part elements matters.
If you reference the XSD in your XML instance document, you now also need to include a reference for the Schematron rule, along the lines of
<?xml-model href="../Desktop/key.xsd" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>

The same table 'name' cannot be the child table in two nested relations

Several time already asked here and there, some answers relate to old VS versions (this on is using V.S. 2012).
I present the problem again:
given an xsd:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="LocationType">
<xs:attribute name="X" type="xs:integer" />
<xs:attribute name="Y" type="xs:integer" />
</xs:complexType>
<xs:complexType name="AlphaNumericType">
<xs:sequence>
<xs:element name="AlphaNumericLocation" type="LocationType" />
</xs:sequence>
<xs:attribute name="id" type="xs:string" />
<xs:attribute name="key" type="xs:integer" />
</xs:complexType>
<xs:complexType name="BitmapType">
<xs:sequence>
<xs:element name="BitmapLocation" type="LocationType" />
<xs:element name="BitmapCaptions" type="AlphaNumericType" />
</xs:sequence>
<xs:attribute name="key" type="xs:string" />
<xs:attribute name="id" type="xs:string" />
</xs:complexType>
<xs:complexType name="ArcType">
<xs:sequence>
<xs:element name="ArcLocation" type="LocationType" />
<xs:element name="ArcCaptions" type="AlphaNumericType" />
</xs:sequence>
<xs:attribute name="key" type="xs:string" />
<xs:attribute name="id" type="xs:string" />
</xs:complexType>
<xs:element name="BitmapControls">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="Bitmap" type="BitmapType" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="ArcControls">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="Arc" type="ArcType" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Notice - that AlphaNumeric has a location element, and both bitmap and arc has AlphaNumeric.
When I create a cs class (using XSD tool) and try to instantiate it I get this error:
The same table 'AlphaNumericLocation' cannot be the child table in two
nested relations.
How can I overcome this issue ?
(the real xsd is more complicated and has a lot more "related similar" children.....
I want to use the xml data in my app in a typed dataset (which easily read and parse the xml).
and I can easily bind tables and columns to other controls... (grid)
Microsoft's XML parser does not support this: I don't think it's changed since early versions of VS.
Check here for some hints on what to do instead: http://social.msdn.microsoft.com/Forums/en-US/22f98352-83b9-4638-a306-34a36a11e4d6/the-same-table-choice-cannot-be-the-child-table-in-two-nested-relations
I have posted a workaround for this problem.
Obviously it may not be a solution for every one,
but at least it explains the source of the problem an points a finger to the offending code.
Serialization Issue when using WriteXML method
Also, you should use 'nesting' in your schema, that will fix the problem.
I have problems adapting your schema, so you'll have to try yourself, but I have adapted one of my own. It's a DataSet with two tables, where MyRootTable has a nested relation with 'PremiumPerYear'.
The key player in this nested relation is the <xs:choice element.
It allows (I believe) the schema to reference another part of itself.
This reference is then created/used by the 'ref' keyword:
<xs:element ref="PremiumPerYear" />
Note: this example does not have an actual 'double nested' relation, but that's just because I cut 90kb of text out.
<DataSet>
<xs:schema id="NewDataSet" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:msprop="urn:schemas-microsoft-com:xml-msprop">
<xs:element name="PremiumPerYear">
<xs:complexType>
<xs:sequence>
<xs:element name="BeforeTaxes" type="xs:decimal" minOccurs="0" />
<xs:element name="AfterTaxes" type="xs:decimal" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="PremiumPerYear" />
<xs:element name="MyRootTable">
<xs:complexType>
<xs:sequence>
<xs:element name="RequestType" msprop:KeyValueCategory="KindOfRequest" type="xs:string" minOccurs="0" />
<xs:element name="RequestDateTime" type="xs:dateTime" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
</DataSet>

Schema Validation Warnings and Errors

When I run the xsd tool to generate vb classes against:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" attributeFormDefault="qualified" elementFormDefault="qualified">
<xs:element name="Security" type="SecurityType"/>
<xs:complexType name="SecurityType">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="UsernameToken" type="UsernameToken"/>
</xs:sequence>
<xs:attribute name="mustUnderstand" type="xs:string"/>
<xs:anyAttribute/>
</xs:complexType>
<xs:complexType name="UsernameToken">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Username" type="xs:string"/>
<xs:element minOccurs="0" maxOccurs="1" name="Password" type="Password"/>
</xs:sequence>
<xs:attribute name="Id" type="xs:string"/>
</xs:complexType>
<xs:complexType name="Password">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="Type" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
I get the following schema validation warnings:
Type Password is not declared
Type UsernameToken is not declared
Type SecurityType is not declared
I get the following Error:
The datatype 'SecurityType' is missing
I added xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" and it worked.

Categories

Resources