Error while validating XML - c#

System.ArgumentNullException: value cannot be undefined
StackTrace:
at System.Xml.Linq.XAttribute..ctor(XName name, Object value)
at System.Xml.Schema.XNodeValidator.ValidateAttributes(XElement e)
at System.Xml.Schema.XNodeValidator.ValidateElement(XElement e)
at System.Xml.Schema.XNodeValidator.ValidateNodes(XElement e)
at System.Xml.Schema.XNodeValidator.ValidateElement(XElement e)
at System.Xml.Schema.XNodeValidator.Validate(XObject source, XmlSchemaObject partialValidationType, Boolean addSchemaInfo)
at System.Xml.Schema.Extensions.Validate(XDocument source, XmlSchemaSet schemas, ValidationEventHandler validationEventHandler, Boolean addSchemaInfo)
Source code:
var xmlPath = #"C:\XSDTEST\test.xml";
XDocument doc = XDocument.Load(xmlPath);
XmlSchemaSet xss = new XmlSchemaSet();
xss.Add("",#"C:\XSDTEST\test.xsd");
XmlReaderSettings xrs = new XmlReaderSettings();
xrs.ValidationType = ValidationType.Schema;
xrs.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
xrs.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
xrs.ValidationFlags |= XmlSchemaValidationFlags.ProcessIdentityConstraints;
xrs.Schemas = xss;
doc.Validate(xss, new ValidationEventHandler((s, args) => { }), true);
test.xsd:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="Root">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Child1" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="Child2" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Child2" type="Child2ElemType"/>
<xsd:complexType name="Child2ElemType">
<xsd:attribute ref="align" default="left"/>
</xsd:complexType>
<xsd:attribute name="align" type="alignAttType"/>
<xsd:simpleType name="alignAttType">
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="left"/>
<xsd:enumeration value="right"/>
<xsd:enumeration value="center"/>
<xsd:enumeration value="justify"/>
<xsd:enumeration value="char"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
test.xml:
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:///C:/XSDTEST/test.xsd">
<Child1/>
<Child2/>
</Root>
The problem: default="left":
<xsd:attribute ref="align" default="left"/>
I think the validation process tries to create an "align" attribute with a default value, but the XAttribute constructor gets null, not "left".
If I set default value at <xsd:attribute name="align" type="alignAttType" default="left"/> it works fine.
If I set default value at <xsd:attribute ref="align" default="left"/> I will get the error.
Can I disable the creation of attributes with default values during the validation process?
or
What are the settings for correctly handling the default values?

Based on the XSD, the "ref=" must be a "Qualified Name"
https://msdn.microsoft.com/en-us/library/ms256143(v=vs.110).aspx
The ref value must be a qualified name (QName)
Since you have an XSD without a namespace, it looks like the validator is not able to find the referenced attribute.
Also, take a look at this related SO question:
How to reference an attribute in xsd
in XML Schemas all global element, attribute or type definitions must be qualified
The following is the relevant Standard extract:
https://www.w3.org/TR/REC-xml-names/#defaulting
Default namespace declarations do not apply directly to attribute names
The namespace name for an unprefixed attribute name always has no value
The following link talks specifically about the unqualified global attributes
Unqualified XSD global attribute references

After loading schemas I founded temporary workaround:
foreach (XmlSchema schema in xss.Schemas())
{
foreach (System.Collections.DictionaryEntry ag in schema.AttributeGroups)
{
if (ag.Value is XmlSchemaAttributeGroup)
{
var attributeGroup = (XmlSchemaAttributeGroup)ag.Value;
foreach (var attributeOrGroup in attributeGroup.Attributes)
{
if (attributeOrGroup is XmlSchemaAttribute)
{
var attribute = (XmlSchemaAttribute)attributeOrGroup;
if (attribute.DefaultValue != null)
{
attribute.DefaultValue = null;
}
if (attribute.FixedValue != null)
{
attribute.FixedValue = null;
}
}
}
}
}
foreach (System.Collections.DictionaryEntry st in schema.SchemaTypes)
{
if (st.Value is XmlSchemaComplexType)
{
var c = (XmlSchemaComplexType)st.Value;
foreach (var g in c.Attributes)
{
if (g is XmlSchemaAttribute)
{
var attr = (XmlSchemaAttribute)g;
if (attr.DefaultValue != null)
{
attr.DefaultValue = null;
}
if (attr.FixedValue != null)
{
attr.FixedValue = null;
}
}
}
}
}
}

Related

CDATA section as string using service reference

Using c# and visual studio 2015
I'm working with an external webservice and I have build a service reference using a delivered WSDL. That is all working, and I can call the service, but I get a error because the request is not in correct format...
Part of the service definition is this:
<xsd:complexType name="GCTPLookupRequestType">
<xsd:sequence>
<xsd:element name="gctpMessage" type="xsd:string" minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
The gctpMessage is a string element but is expected to contain a CDATA section like this:
<![CDATA[
<Gctp v="1.0">
<System r="CprSoeg">
<Service r="STAM+">
<CprServiceHeader r="STAM+">
<Key>
<Field r="PNR" v="0000000000"/>
</Key>
</CprServiceHeader>
</Service>
</System>
</Gctp>
]]>
If I append this as a string as expected to the gctpMessage property all seems fine, but when I inspect the request using Fiddler I se that it is all wrong:
<gctpMessage>
<![CDATA[<Gctp v="1.0"><System r="CprSoeg"><
Service r="STAM+"><CprServiceHeader r="STAM+"><Key><
Field r="PNR" v="0000000000"/></Key></CprServiceHeader></
Service></System></Gctp>]]>
</gctpMessage>
I know this is caused by the XML serializer enterpreting this as a string and therefore escapes the tags.
But how do I get around this? The WSDL has defined it as a string and I really want to use the service reference but I do not know how to handle this...
Changing the service is not an option.
Any suggestion would be appriciated :)
Just perfect dbc, it did the trick :)
Thanks for that..
[System.Xml.Serialization.XmlIgnore]
public string gctpMessage {
get {
return this.gctpMessageField;
}
set {
this.gctpMessageField = value;
this.RaisePropertyChanged("gctpMessage");
}
}
[System.Xml.Serialization.XmlElementAttribute(Order = 1, ElementName = "gctpMessage")]
public XmlNode[] CDataContent
{
get
{
var dummy = new XmlDocument();
return new XmlNode[] { dummy.CreateCDataSection(gctpMessage) };
}
set
{
if (value == null)
{
gctpMessage = null;
return;
}
if (value.Length != 1)
{
throw new InvalidOperationException(
String.Format(
"Invalid array length {0}", value.Length));
}
gctpMessage = value[0].Value;
}
}

Connecting to Salesforce Problems C#

I am getting the following error and can not seem to figure out why.
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.dll
Additional information: Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'iDdataPrep.SFDC.ListViewRecordColumn[]' to 'iDdataPrep.SFDC.ListViewRecordColumn'
error CS0030: Cannot convert type 'iDdataPrep.SFDC.ListViewRecordColumn[]' to 'iDdataPrep.SFDC.ListViewRecordColumn'
error CS0029: Cannot implicitly convert type 'iDdataPrep.SFDC.ListViewRecordColumn' to 'iDdataPrep.SFDC.ListViewRecordColumn[]'
error CS0029: Cannot implicitly convert type 'iDdataPrep.SFDC.ListViewRecordColumn' to 'iDdataPrep.SFDC.ListViewRecordColumn[]'
Here is my code:
public static void sfLogin()
{
string userName = "***";
string password = "***";
string securityToken = "***";
SFDC.SforceService sfdcBinding = null;
SFDC.LoginResult currentLoginResult = null;
sfdcBinding = new SFDC.SforceService();
try
{
currentLoginResult = sfdcBinding.login(userName, password);
}
catch (System.Web.Services.Protocols.SoapException ex)
{
sfdcBinding = null;
MessageBox.Show(ex.Message);
}
catch(Exception ex)
{
sfdcBinding = null;
MessageBox.Show(ex.Message);
}
sfdcBinding.Url = currentLoginResult.serverUrl;
sfdcBinding.SessionHeaderValue = new SFDC.SessionHeader();
sfdcBinding.SessionHeaderValue.sessionId = currentLoginResult.sessionId;
}
Some .Net integrations with Salesforce do fail due to a bug in .NET's XmlSerializer as described in the this link.
The workaround is to add the following element to the Enterprise.WSDL.XML file:
<xsd:attribute name="tmp" type="xsd:string" />
in the ListViewRecord section. Your Enterprise.WSDL.XML should look like :
<complexType name="ListViewRecord">
<sequence>
<element name="columns" type="tns:ListViewRecordColumn" maxOccurs="unbounded"/>
</sequence>
<b>
<xsd:attribute name="tmp" type="xsd:string" />
</b>
</complexType>
Check out more in this link.
I just ran into this problem. Here is work around I used. Before you generate the proxy file from the wsdl (such as partner.wsdl), edit the file and add a dummy field to the ListViewRecord defintion.
<complexType name="ListViewRecord">
<sequence>
<element name="columns" type="tns:ListViewRecordColumn" minOccurs="1" maxOccurs="unbounded"/>
<element name="dummy" type="xsd:int"/>
</sequence>
</complexType>
When you generate the proxy file with wsdl.exe it will generate the classes ListViewRecord and ListViewRecordColumn correctly. Then delete the dummy field from the generated code and the classes and properties will be defined as they should be.
public partial class ListViewRecord {
private ListViewRecordColumn[] columnsField;
/// ** delete this member variable **
private int dummyField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("columns")]
public ListViewRecordColumn[] columns {
get {
return this.columnsField;
}
set {
this.columnsField = value;
}
}
/// ** delete this property **
public int dummy {
get {
return this.dummyField;
}
set {
this.dummyField = value;
}
}
}
There are two references to ListViewRecordColumn[][] in Reference.cs.
Change them both to ListViewRecordColumn[].

Xml Xsd Validation Fails (xs:anyType)

I have this XML file
<bookstore>
<test>
<test2/>
</test>
</bookstore>
and this XSD schema
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="bookstore" type="bookstoreType"/>
<xsd:complexType name="bookstoreType">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="test" type="xsd:anyType" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
I intend to validate xml file from C# code.
There is a method that validate XML file:
// validate xml
private void ValidateXml()
{
_isValid = true;
// Get namespace from xml file
var defaultNamespace = XDocument.Load(XmlFileName).Root.GetDefaultNamespace().NamespaceName;
// Set the validation settings.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.Schemas.Add(defaultNamespace, XsdFileName);
settings.ValidationEventHandler += OnValidationEventHandler;
// Create the XmlReader object.
using(XmlReader reader = XmlReader.Create(XmlFileName, settings))
{
// Parse the file.
while (reader.Read()) ;
}
}
private void OnValidationEventHandler(object s, ValidationEventArgs e)
{
if (_isValid) _isValid = false;
if (e.Severity == XmlSeverityType.Warning)
MessageBox.Show("Warning: " + e.Message);
else
MessageBox.Show("Validation Error: " + e.Message);
}
I know, this XML file is valid. But my code reterns this Error:
Validation Error: Could not find schema information for the element 'test2'
Where is my mistake?
Thanks!!!
UPDATE: I assume your code matches the error you listed (I've tried your code on .NET 3.5SP1, and I wasn't able to reproduce your behaviour). The workaround below should work for sure (the error you're getting is consistent to a process contents clause strict as opposed to lax).
Replace <xsd:element name="test" type="xsd:anyType" /> with a complex content that allows for xsd:any, like this:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="bookstore" type="bookstoreType"/>
<xsd:complexType name="bookstoreType">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="test">
<xsd:complexType>
<xsd:sequence>
<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
Having "lax" will still yield a message; you could use "skip" if you want that message gone. Regardless, skip and lax in an xsd:any gives you what you need.

Getting started with XSD validation with .NET

Here is my first attempt at validating XML with XSD.
The XML file to be validated:
<?xml version="1.0" encoding="utf-8" ?>
<config xmlns="Schemas" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="config.xsd">
<levelVariant>
<filePath>SampleVariant</filePath>
</levelVariant>
<levelVariant>
<filePath>LegendaryMode</filePath>
</levelVariant>
<levelVariant>
<filePath>AmazingMode</filePath>
</levelVariant>
</config>
The XSD, located in "Schemas/config.xsd" relative to the XML file to be validated:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="config">
<xs:complexType>
<xs:sequence>
<xs:element name="levelVariant">
<xs:complexType>
<xs:sequence>
<xs:element name="filePath" type="xs:anyURI">
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Right now, I just want to validate the XML file precisely as it appears currently. Once I understand this better, I'll expand more. Do I really need so many lines for something as simple as the XML file as it currently exists?
The validation code in C#:
public void SetURI(string uri)
{
XElement toValidate = XElement.Load(Path.Combine(PATH_TO_DATA_DIR, uri) + ".xml");
// begin confusion
// exception here
string schemaURI = toValidate.Attributes("xmlns").First().ToString()
+ toValidate.Attributes("xsi:noNamespaceSchemaLocation").First().ToString();
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add(null, schemaURI);
XDocument toValidateDoc = new XDocument(toValidate);
toValidateDoc.Validate(schemas, null);
// end confusion
root = toValidate;
}
Running the above code gives this exception:
The ':' character, hexadecimal value 0x3A, cannot be included in a name.
Any illumination would be appreciated.
Rather than using the XDocument.Validate extension method, I would use an XmlReader which can be configured to process an inline schema via XmlReaderSettings. You could do some thing like the following code.
public void VerifyXmlFile(string path)
{
// configure the xmlreader validation to use inline schema.
XmlReaderSettings config = new XmlReaderSettings();
config.ValidationType = ValidationType.Schema;
config.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
config.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
config.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
config.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
// Get the XmlReader object with the configured settings.
XmlReader reader = XmlReader.Create(path, config);
// Parsing the file will cause the validation to occur.
while (reader.Read()) ;
}
private void ValidationCallBack(object sender, ValidationEventArgs vea)
{
if (vea.Severity == XmlSeverityType.Warning)
Console.WriteLine(
"\tWarning: Matching schema not found. No validation occurred. {0}",
vea.Message);
else
Console.WriteLine("\tValidation error: {0}", vea.Message);
}
The code above assumes the following using statements.
using System.Xml;
using System.Xml.Schema;
Just to keep this simple I did not return a boolean or a collection of validation errors, you could easily modify this to do so.
Note: I modified your config.xml and config.xsd to get them to validate. These are the changes I made.
config.xsd:
<xs:element maxOccurs="unbounded" name="levelVariant">
config.xml:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="config.xsd">
Following is out of a working sample:
Usage:
XMLValidator val = new XMLValidator();
if (!val.IsValidXml(File.ReadAllText(#"d:\Test2.xml"), #"D:\Test2.xsd"))
MessageBox.Show(val.Errors);
Class:
public class CXmlValidator
{
private int nErrors = 0;
private string strErrorMsg = string.Empty;
public string Errors { get { return strErrorMsg; } }
public void ValidationHandler(object sender, ValidationEventArgs args)
{
nErrors++;
strErrorMsg = strErrorMsg + args.Message + "\r\n";
}
public bool IsValidXml(string strXml/*xml in text*/, string strXsdLocation /*Xsd location*/)
{
bool bStatus = false;
try
{
// Declare local objects
XmlTextReader xtrReader = new XmlTextReader(strXsdLocation);
XmlSchemaCollection xcSchemaCollection = new XmlSchemaCollection();
xcSchemaCollection.Add(null/*add your namespace string*/, xtrReader);//Add multiple schemas if you want.
XmlValidatingReader vrValidator = new XmlValidatingReader(strXml, XmlNodeType.Document, null);
vrValidator.Schemas.Add(xcSchemaCollection);
// Add validation event handler
vrValidator.ValidationType = ValidationType.Schema;
vrValidator.ValidationEventHandler += new ValidationEventHandler(ValidationHandler);
//Actual validation, read conforming the schema.
while (vrValidator.Read()) ;
vrValidator.Close();//Cleanup
//Exception if error.
if (nErrors > 0) { throw new Exception(strErrorMsg); }
else { bStatus = true; }//Success
}
catch (Exception error) { bStatus = false; }
return bStatus;
}
}
The above code validates following xml(code3) against xsd(code4).
<!--CODE 3 - TEST1.XML-->
<address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test1.xsd">
<name>My Name</name>
<street>1, My Street Address</street>
<city>Far</city>
<country>Mali</country>
</address>
<!--CODE 4 - TEST1.XSD-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
In validating against your xml/xsd I get of errors different than yours; I think this can help you continue(add/remove xml elements) from here:
You may also try the reverse process; try generating the schema from your xml and compare with your actual xsd - see the difference; and the easiest way to do that is to use generate schema using VS IDE. Following is how you'd do that:
Hope this helps.
--EDIT--
This is upon John's request, please see updated code using non deprecated methods:
public bool IsValidXmlEx(string strXmlLocation, string strXsdLocation)
{
bool bStatus = false;
try
{
// Declare local objects
XmlReaderSettings rs = new XmlReaderSettings();
rs.ValidationType = ValidationType.Schema;
rs.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation | XmlSchemaValidationFlags.ReportValidationWarnings;
rs.ValidationEventHandler += new ValidationEventHandler(rs_ValidationEventHandler);
rs.Schemas.Add(null, XmlReader.Create(strXsdLocation));
using (XmlReader xmlValidatingReader = XmlReader.Create(strXmlLocation, rs))
{ while (xmlValidatingReader.Read()) { } }
////Exception if error.
if (nErrors > 0) { throw new Exception(strErrorMsg); }
else { bStatus = true; }//Success
}
catch (Exception error) { bStatus = false; }
return bStatus;
}
void rs_ValidationEventHandler(object sender, ValidationEventArgs e)
{
if (e.Severity == XmlSeverityType.Warning) strErrorMsg += "WARNING: " + Environment.NewLine;
else strErrorMsg += "ERROR: " + Environment.NewLine;
nErrors++;
strErrorMsg = strErrorMsg + e.Exception.Message + "\r\n";
}
Usage:
if (!val.IsValidXmlEx(#"d:\Test2.xml", #"D:\Test2.xsd"))
MessageBox.Show(val.Errors);
else
MessageBox.Show("Success");
Test2.XML
<?xml version="1.0" encoding="utf-8" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test2.xsd">
<levelVariant>
<filePath>SampleVariant</filePath>
</levelVariant>
<levelVariant>
<filePath>LegendaryMode</filePath>
</levelVariant>
<levelVariant>
<filePath>AmazingMode</filePath>
</levelVariant>
</config>
Test2.XSD (Generated from VS IDE)
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="config">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="levelVariant">
<xs:complexType>
<xs:sequence>
<xs:element name="filePath" type="xs:anyURI">
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
This is guaranteed to work!
Your code to extract the schema location looks weird. Why do you get the value of the xmlns attribute and concatenate it with the value of the xsi:noNamespaceSchemaLocation attribute? The exception is caused by the fact that you cannot specify a prefix in a call to Attributes; you need to specify the desired XNamespace.
Try this (untested):
// Load document
XDocument doc = XDocument.Load("file.xml");
// Extract value of xsi:noNamespaceSchemaLocation
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
string schemaURI = (string)doc.Root.Attribute(xsi + "noNamespaceSchemaLocation");
// Create schema set
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("Schemas", schemaURI);
// Validate
doc.Validate(schemas, (o, e) =>
{
Console.WriteLine("{0}", e.Message);
});

What is the best way to create an XML document conforming to an XSD Schema?

I have an XSD and I have to generate an XML document to send to the customers of the company I work with. The documents I send will be validated against this XSD schema.
What is the best way to create a XML document conforming to a XSD Schema? I mean, I'm searching for best practices and the like. I'm new to this and while "Googling" around here and there, I found people using XmlTextWriter, DataSet.WriteXml, and others.
DataSet.WriteXml seems to not work well for me. This is what I did:
var ds = new DataSet();
ds.ReadXmlSchema(schemaFile);
ds.Tables["TableName"].Rows.Add("", "", 78, true, DateTime.Now);
...
ds.WriteXml("C:\\xml.xml");
I found it generates a node with NewDataSet, and the nodes are not in the proper order.
XmlTextWriter, I find it a bit long to do... but I will if there is no other choice.
What do you think is the best way to do this? Are there other approaches to do it?
I would put the schema here if it wasn't so long, and if it were relevant to the question.
The mainstream practice in .NET is to use XML Serialization.
In your case, I would do this:
run the xsd.exe too on .XSD to generate source code for classes (xsd /c)
build your app that utilizes those generated classes. Keep in mind you can extend those classes via the "partial classes" technique
in code, instantiate an XmlSerializer, and Serialize the class instances.
Example:
Given this schema:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Foo" nillable="true" type="Foo" />
<xs:complexType name="Foo">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Bar" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="1" name="Baz" type="UntypedArray" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="UntypedArray">
<xs:choice minOccurs="1" maxOccurs="unbounded">
<xs:element name="Type1" type="Type1" minOccurs="1" maxOccurs="1"/>
<xs:any namespace="##other" processContents="lax" minOccurs="1" maxOccurs="1"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="Type1" mixed="true">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Child" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>
xsd.exe generates this source code:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=true)]
public partial class Foo {
private string barField;
private object[] bazField;
/// <remarks/>
public string Bar {
get {
return this.barField;
}
set {
this.barField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("", typeof(System.Xml.XmlElement), IsNullable=false)]
[System.Xml.Serialization.XmlArrayItemAttribute(typeof(Type1), IsNullable=false)]
public object[] Baz {
get {
return this.bazField;
}
set {
this.bazField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
public partial class Type1 {
private string childField;
private string[] textField;
/// <remarks/>
public string Child {
get {
return this.childField;
}
set {
this.childField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTextAttribute()]
public string[] Text {
get {
return this.textField;
}
set {
this.textField = value;
}
}
}
In your app you can instantiate a Foo and then serialize, like this:
Foo foo = new Foo();
// ...populate foo here...
var builder = new System.Text.StringBuilder();
XmlSerializer s = new XmlSerializer(typeof(Foo));
using ( var writer = System.Xml.XmlWriter.Create(builder))
{
s.Serialize(writer, foo, ns);
}
string rawXml = builder.ToString();
This example serializes into a string. Of course you can serialize to other XmlWriters, you can write out to a file, to any arbitrary stream, and so on.
Normally I tweak the serialization to omit the XML declaration, omit the default xml namespaces, and so on. Like this:
Foo foo = new Foo();
// ...populate foo here...
var builder = new System.Text.StringBuilder();
var settings = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
var ns = new XmlSerializerNamespaces();
ns.Add("","");
XmlSerializer s = new XmlSerializer(typeof(Foo));
using ( var writer = System.Xml.XmlWriter.Create(builder, settings))
{
s.Serialize(writer, foo, ns);
}
string rawXml = builder.ToString();
You can also do the reverse - map from an XML document to an in-memory object graph - using the XmlSerializer. Use the Deserialize method.
A post I wrote a while ago may be of interest to you. I had to work with BizTalk and found that generating my classes from an XSD and then serializing that class over the wire (wa-la XML) worked quite well!
http://blog.andrewsiemer.com/archive/2008/04/30/accepting-xmldocuments-from-biztalk-de-serializing-them-to-xsd-generated-serializable.aspx
This allows you to work with the data as a class and all the perks that go along with that. And it totally allows you to bypass the XML writers!
Such a great reference ..
http://msdn.microsoft.com/en-us/library/x6c1kb0s%28v=vs.110%29.aspx
I just generated classes with fields for csharp:
First you open visual studio command prompt (programs->visualStudio->visualstudioTools->VisualstudioCommandPrompt)
Then you change to the directory of your xsd file and then run the following command:
xsd /classes /fields /language:CS MyXSDSCHEMAFILE.xsd
(replace the MyXSDSCHEMAFILE.xsd with your xsd file name)
After your cs file is created, copy it into your project folder where all the other cs file are and add it to the project in visual studio by right clicking the project and adding existing item. Once that is completed go to your code segment where you want to use your class and initialize like this (classname is the class that was created in the cs file):
classname myvariablename = new classname(); // so easy :)
// now you just fill with content
myvariablename.whatever.andever.field = "JaWerHatDasErfunden";// you just set a field
then serialize as xml (tons of examples on the web )
Useful Hint:
Be aware that instantiation is not always part of the xsd created classes.
Make sure you create your objects properly to avoid Null Pointer exceptions.
You can create the XML and then run it through an Xml Schema Validator that I wrote.

Categories

Resources