XSD element with one xml child and then content (including html/xml) - c#

I have an xml document that contains some html.
<begin-line>
<verse-num>6</verse-num>a mixed people<footnote id="f2">
Or <i>a foreign people</i>; Hebrew <i>a bastard</i>
</footnote> shall dwell in Ashdod,
</begin-line>
The verse-num element is the only element I wan't validated, the rest I want valideted to one large group of a string type, which can hold html, and also sometimes some more xml (like footnote).
Here is the schema I have right now which doesn't do the trick.
<xs:element maxOccurs="unbounded" name="begin-line">
<xs:complexType mixed="true">
<xs:sequence minOccurs="0">
<xs:choice maxOccurs="unbounded">
<xs:element name="verse-num">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:unsignedByte">
<xs:attribute name="begin-chapter" type="xs:unsignedByte" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:sequence>
<xs:attribute name="class" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
I am using XSD.exe to generate a class that I can deserialize this junk into.
It is generating a begin-line object with a verse-num type below it, and also an array of text, which are split by the html/xml tags inside of .
What I need is an xsd that can be used by XSD.exe to generate a begin-line class that will give me a verse-num type, and then one string property that will contain the rest of the content (including text, i's, b's, footnotes, xml/html).
I did some research and it seems like processContents will do the trick, but I can't figure out where to put it.
When it comes down to it, I want to program against the object created by the XSD.exe like this.
var beginLine = new crosswaybiblePassageVerseunitBeginline();
Console.WriteLine((beginLine.Items[0] as crosswaybiblePassageVerseunitBeginlineVersenum).Value);
Console.Write(beginLine.Text);
or maybe even...
var beginLine = new crosswaybiblePassageVerseunitBeginline();
Console.WriteLine(beginLine.Versenum.Value);
Console.Write(beginLine.Text);

I'm not sure how to setup the schema such that it'll provide nice output from XSD.exe but you can specify "any number of elements with any name" in the output using a type with the definition:
<xs:complexType name="AnyChildren">
<xs:sequence>
<xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded" namespace="##any"/>
</xs:sequence>
<xs:anyAttribute />
</xs:complexType>
For example to validate:
<Module>
<Title>Hello World</Title>
<ProviderType>xyz</ProviderType>
<Content />
<MoreContent />
</Module>
You could use:
<xs:complexType name="Module">
<xs:sequence>
<xs:element name="Title" type="xs:string" maxOccurs="1" />
<xs:element name="ProviderType" type="xs:string" minOccurs="1" nillable="false" />
<xs:any processContents="skip" minOccurs="0" maxOccurs="unbounded" namespace="##any"/>
</xs:sequence>
<xs:anyAttribute />
</xs:complexType>

Related

How define two elements with same name with same type in two different position in schema

I have a scenario where i have xml schema with same element name with same type at two different positions. Some xml will have the element in first position and few other xml are having the element in the second position.
<xs:element minOccurs="0" maxOccurs="1" name="DisplayUnit" type="DisplayUnit" />
<xs:element minOccurs="0" maxOccurs="1" name="Serial" type="Serial" />
<xs:element minOccurs="0" maxOccurs="1" name="DisplayUnit" type="DisplayUnit"/>
In my xml some time DisplayUnit comes above serial and some time after that. How i handle this scenario?
I have one more clarification. In this below scenario the element is not a type but a property. The position can be either above or below output element, but occurs only once like the first scenario.
<xs:element minOccurs="0" maxOccurs="0" name="MaxA" nillable="true" type="xs:unsignedInt" />
<xs:element minOccurs="0" maxOccurs="0" name="Output" type="Output" />
<xs:element minOccurs="0" maxOccurs="1" name="MaxA" nillable="true" type="xs:unsignedInt" />
I searched a lot but i didn't get any solution.
Any immediate help in this regard is appreciated.
Your question has two parts: the XSD part and the parser part.
XSD
Your XSD does not fit for the result you want to achieve. As it is written, it is possible that the DisplayUnit element occurrs twice in your document. There are two ways to resolve this, depending on your scenario.
If the DisplayUnit and Serial elements are the only elements in the sequence or the entire sequence can be in any order, you can use <xs:all> instead of <xs:sequence>. <xs:all> allows the elements to be in any order:
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="DisplayUnit" type="DisplayUnit" />
<xs:element minOccurs="0" maxOccurs="1" name="Serial" type="Serial" />
</xs:all>
If this is not an option for you, because the other elements are expected to be in sequence, you can replace that part of the sequence by an <xs:choice>:
<xs:choice>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="DisplayUnit" type="DisplayUnit" />
<xs:element minOccurs="0" maxOccurs="1" name="Serial" type="Serial" />
</xs:sequence>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Serial" type="Serial" />
<xs:element minOccurs="0" maxOccurs="1" name="DisplayUnit" type="DisplayUnit" />
</xs:sequence>
</xs:choice>
Parsing in C#
Once you have fixed your XSD and you have validated your document, you know that there is exactly zero or one occurrence of the DisplayUnit and Serial tags. Then you can simply load the XML into an XDocument or XmlDocument (if you didn't do that already) and simply access the elements by their name (regardles of order):
//Assuming there is an XElement named parentElement
XElement displayUnitElement = parentElement.Element("DisplayUnit");
if (displayUnitElement != null) {
//...
}
XElement serialElement = parentElement.Element("Serial");
if (serialElement != null) {
//...
}
On more complex XML you can also use XPath. Once your document validates against the XSD, you can be sure about its structure.

Why does this XML validate, when it shouldn't?

I have the following XSD files:
ReadFile.xsd:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="elsag:lprcore" elementFormDefault="qualified" targetNamespace="elsag:lprcore" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:include schemaLocation="Read.xsd" />
<xs:element name="reads" type="ReadFile" />
<xs:complexType name="ReadFile">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="read" nillable="true" type="read">
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
Read.xsd:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="elsag:lprcore" elementFormDefault="qualified" targetNamespace="elsag:lprcore" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:include schemaLocation="Snapshot.xsd"/>
<xs:include schemaLocation="GPS.xsd"/>
<xs:simpleType name="guid">
<xs:restriction base="xs:string">
<xs:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" />
</xs:restriction>
</xs:simpleType>
<xs:element name="read" type="read"/>
<xs:complexType name="read">
<xs:complexContent mixed="false">
<xs:extension base="snapshot">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="timestamp" type="xs:dateTime" />
<xs:element minOccurs="1" maxOccurs="1" name="plate" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="1" name="state" type="xs:string" />
<xs:element minOccurs="1" maxOccurs="1" name="confidence" type="xs:int" />
<xs:element minOccurs="1" maxOccurs="1" name="overviews">
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="snapshot" type="snapshot"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element minOccurs="1" maxOccurs="1" name="gps" type="gps" />
</xs:sequence>
<xs:attribute name="id" type="guid" use="required" />
<xs:attribute name="camera" type="xs:string" use="required" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Please note that there are more files that make up the XSD, but I don't believe they're relevant to the problem so I did not include them.
I'm using the following code to validate XML files being processed. I want to reject any file that doesn't validate without errors:
StringBuilder validationErrors = new StringBuilder();
inDoc.Validate( schemas, ( o, e ) => {
validationErrors.AppendLine( e.Message );
} );
if ( !string.IsNullOrWhiteSpace( validationErrors.ToString() ) ) {
. . .
}
I've passed the following XML file to the code above and the code does not generate any validation error messages for it.
<read>
<timestamp>2015-07-17T16:20:18.1540000-04:00</timestamp>
<plate>FED456</plate>
</read>
I would have thought that the lack of the reads tag surrounding the read tag would have caused the XML to fail validation. Is the problem in the validation code or is it in the XSD or is this normal?
EDIT:
Here is the code that initializes the schemas variable:
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add( "elsag:lprcore", #"XML\ReadFile.xsd" );
Because you have defined
<xs:element name="read" type="read"/>
the read element is a valid root element for your XML. Every element which is an immediate child of <xs:schema> is eligible for being a root element (even those in an included schema).
Thanks to information posted in the answer by Glorfindel and the link posted by overslacked, I've been able to get the XML validation in my program to work.
The problem was that the program would not flag an XML file that does not contain a namespace as invalid. The cause is that the XDocument.Validate extension method creates an XmlReader object whose XmlReaderSettings property does not contain the ReportValidationWarnings flag. As a result, the ValidationEventHandler delegate passed to the method is not called for these files.
To make the validation logic work, I defined a new extension method that includes the flag:
internal static class XmlValidationExtension {
public static void ValidateWithWarnings( this XDocument doc, XmlSchemaSet schemas, ValidationEventHandler validationCallback ) {
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.Schemas.Add( schemas );
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationEventHandler += new ValidationEventHandler( validationCallback );
XmlReader reader = XmlReader.Create( doc.CreateReader(), settings );
while ( reader.Read() ) ;
}
}
This is essentially the same exact code from the question linked to by overslacked, but where the XmlReader is created by calling the XDocment object's CreateReader method.
This code now considers any XML file which does not use the correct namespace to be invalid. Any other part of the XML that does not match the XSD is also flagged.

Create multiple instances of class to match XML

I have been provided the following XML request as a model to follow along with the WSDL.
<xs:complexType name="commonInput">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="propertyList" nillable="true" type="tns:commonProperty" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="commonProperty">
<xs:sequence>
<xs:element minOccurs="0" name="context" type="xs:string" />
<xs:element minOccurs="0" name="name" type="xs:string" />
<xs:element minOccurs="0" name="value" type="xs:string" />
</xs:sequence>
</xs:complexType>
I am expected to create a response in code using these types to create something similar to the following
<commonInput>
<loginId></loginId>
<propertyList>
<context></context>
<name></name>
<value></value>
</propertyList>
<propertyList>
<context></context>
<name></name>
<value></value>
</propertyList>
</commonInput>
The issue I'm encountering is that I cannot figure out how to create this structure in code since the commonInput.propertyList is not an array or list, it is simply a class.
How can I create multiple instances of propertyList within the commonInput?
Your class commonInput has an attribute called propertyList, which is a sequence of entities of type commonProperty. Note the <xs:sequence> tags that enclose its definition.
So you should be able to use something like:
private List<CommonProperty> propertyList = new ArrayList<CommonProperty>();
I'm not exactly sure what translation you use from XML to your "class".
We use Jaxb to translate between XML and java classes automatically.
In response to your comment, I will try to clarify with an example:
Our WSDL defines:
<s:complexType name="ArrayOfTEKLeverancierObj">
<s:sequence>
<s:element minOccurs="0" maxOccurs="unbounded" name="TEKLeverancierObj"
nillable="true" type="tns:TEKLeverancierObj" />
</s:sequence>
</s:complexType>
And in our java class this translates to:
public class ArrayOfTEKLeverancierObj {
#XmlElement(name = "TEKLeverancierObj", nillable = true)
protected List<TEKLeverancierObj> tekLeverancierObj;

Parsing List<String> into XML using an XML Schema

Looking for an easy way to parse a list of strings (or 2d array[string1,string2])
where string 1 is the name and string 2 is the content.
The result should be an .xml containing only the data of string 2 filled in in all the places where the names of the xml schema are the same as string1.
<xs:include schemaLocation="common.xsd"/>
<xs:complexType name="part1Type">
<xs:all>
<xs:element name="noteCadre1" type="string5000Type" minOccurs="0"/>
<xs:element name="noteCadre2" type="string5000Type" minOccurs="0"/>
<xs:element name="noteCadre3" type="string5000Type" minOccurs="0"/>
<xs:element name="noteCadre4" type="string5000Type" minOccurs="0"/>
<xs:element name="noteCadre5" type="string5000Type" minOccurs="0"/>
<xs:element name="noteCadre6" type="string5000Type" minOccurs="0"/>
<xs:element name="noteCadre7" type="string5000Type" minOccurs="0"/>
<xs:element name="noteCadre8" type="string5000Type" minOccurs="0"/>
<xs:element name="noteCadre9" type="string5000Type" minOccurs="0"/>
<xs:element name="noteCadre10" type="string5000Type" minOccurs="0"/>
<xs:element name="noteCadre11" type="string5000Type" minOccurs="0"/>
<xs:element name="noteCadre12" type="string5000Type" minOccurs="0"/>
<xs:element name="infoResidence" type="home2Type" minOccurs="0"/>
<xs:complexType name="homeType">
<xs:sequence>
<xs:element name="lieu" type="string150Type"/>
<xs:element name="dateDebut" type="xs:date" minOccurs="0"/>
<xs:element name="dateFin" type="xs:date" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="home2Type">
<xs:sequence>
<xs:element name="item" type="homeType" maxOccurs="2"/>
</xs:sequence>
</xs:complexType>
The List<String> looks like this:
LIST 1 : {noteCadre1, noteCadre2, .... , infoResidence.lieu.1 , infoResidence.dateDebut.1 ,
infoResidence.dateFin.1 , infoResidence.lieu.2 , infoResidence.dateDebut.2 , ...
LIST 2 : {dataCadre1, dataCadre2, .... , Street 100, 01/01/20005, 25/03/2005, ..... }
Any help would be appreciated; browsed the web for a couple of days without any succes..
You can't do that using only XML Schema: XML Schema is about validating XML documents and not about parsing.
To do this kind of things you need to add a first step that transforms your input document (the list of strings) into your target XML representation.
This seems quite easy to achieve using any programming language (including XSLT 2.0) but this is clearly out of the scope of XML schema languages.

Can't get xs:element with attribute

I have XML elements with and without attributes
<xs:element name='element0'>
<xs:complexType name='internationalShoeSize'>
<xs:annotation>
<xs:documentation>Data ...</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:simpleContent>
<xs:extension base='xs:string'>
<xs:attribute name='attribute0' type='xs:string' />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name='element1'>
<xs:complexType name='internationalShoeSize'>
<xs:annotation>
<xs:documentation>Data1 ...</xs:documentation>
</xs:annotation>
</xs:element>
When I get the elements in a DataTable, only get the elements without attributes.
foreach(DataColum colum in table.colums)
{
....
}
This foreach only get the elements without attributes: the element1.
How can I get all the elements, with and without attributes?
I think you need to start with a better schema snippet, the one you've posted is mangled beyond use. I took yours and cleaned it up - in the process maybe deviated from your intentions; feel free to take my sample and used it to edit your question for better illustration.
(Alternatively, if you have a sample XML, post that instead - it might be even easier to explain.)
<?xml version="1.0" encoding="utf-8" ?>
<!-- XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com) -->
<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" xmlns="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="element0" type="internationalShoeSize"/>
<xs:element name="element1" type="internationalShoeSize"/>
<xs:complexType name="internationalShoeSize">
<xs:annotation>
<xs:documentation>Data ...</xs:documentation>
</xs:annotation>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="attribute0" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
Meanwhile, this is the equivalent data structure you would get (on .NET):
Your attribute is there...

Categories