How to create XSD for the given XML? - c#

For the below XML, I need to generate XSD created but getting an error
The 'NewDataSet' element is not declared
<NewDataSet>
<Table>
<SITE>VMD</SITE>
<TANK>65-12-392</TANK>
<SERVICE>HZLPG</SERVICE>
<IP21TAG>BC-BBH-OS-4LI21392</IP21TAG>
</Table>
</NewDataSet>
XSD:
<?xml version="1.0"?>
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="PAS">
<xs:complexType>
<xs:sequence>
<xs:element name="Records">
<xs:complexType>
<xs:sequence>
<xs:element name="Site" type="xs:string" />
<xs:element name="Plant" type="xs:string" />
<xs:element name="Tank" type="xs:string" />
<xs:element name="Service" type="xs:string" />
<xs:element name="IP21Tag" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Can anyone please help how to declare 'NewDataSet' element?
Thanks in advance.

You can generate an XSD from example XML using the xsd.exe supplied from Microsoft. You will only generate an XSD which matches your example so you would need an example to contain all the cases that you wished to parse, or you would have to further edit the XSD to include those.
Anyway this is a good way to get started. MSDN Docs on XSD.exe
Once you have a XSD file you might want to use a tool like XSD2Code which will generate all the code you need to read the XML and turn it into a set of c# objects in memory.
(This assumes you can read all your XML into memory in one go. Otherwise you will need to read your XML using an event SAX type approach.)

to start with, the root element 'NewData' is not declared in your XSD.
I would suggest you take a look at this first: http://www.w3schools.com/schema/schema_example.asp

XmlSchemaInference Class can be used for coverting xml to xsd like:
XmlReader reader = XmlReader.Create ( "contosoBooks.xml" );
XmlSchemaSet schemaSet = new XmlSchemaSet ( );
XmlSchemaInference schema = new XmlSchemaInference ( );
schemaschemaSet = schema.InferSchema ( reader );
foreach ( XmlSchema s in schemaSet.Schemas ( ) )
{
s.Write ( Console.Out );
}
http://msdn.microsoft.com/en-us/library/system.xml.schema.xmlschemainference.aspx
Second way,
Here is example:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "Xsd.exe";
p.StartInfo.Arguments = "C:\\config.xml /outputdir:C:\\Temp";
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine("OUTPUT FROM XSD.EXE : " + output);
This will create config.xsd file from config.xml.
All credit goes to people who answered it on msdn forums.

Related

How can I get all the XSD validation errors from an XML file in dotnet?

Caveat: I'm fairly new to .NET so I'm unfamiliar with a lot of libraries available.
I have developed a function app using java that I'm having to port over to C#. I am currently using the built in XSD validation library for .NET and my file is being successfully validated, however when testing the results against the java version there are significantly less validation errors being reported in the .NET version.
Root XSD file
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="schema_namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="schema_namespace" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:include schemaLocation="included_xsd_1.xsd"/>
<xs:include schemaLocation="included_xsd_2.xsd"/>
<xs:include schemaLocation="included_xsd_3.xsd"/>
<xs:include schemaLocation="included_xsd_4.xsd"/>
<xs:include schemaLocation="included_xsd_5.xsd"/>
<xs:element name="DEMDataSet">
<xs:annotation>
<xs:documentation>Root Tag</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="dCustomElement" type="dCustomElement" id="dElementSection" minOccurs="0">
<xs:annotation>
<xs:documentation>Contains information for custom elements.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Report" id="ReportGroup" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>Container Tag to hold each instance of a record</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="from_included_xsd_1" type="type" id="typeSection">
<xs:annotation>
<xs:documentation>Some Information</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="from_included_2" type="type" id="typeSection" minOccurs="0">
<xs:annotation>
<xs:documentation>Some Information</xs:documentation>
</xs:annotation>
</xs:element>
...
</xs:sequence>
<xs:attribute name="timeStamp" type="DateTimeType" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
My issue appears to be occuring when there is a missing element in one of my included xsd files, when this happens all subsequent errors in that xsd file are not reported (e.g. if the initial element is missing, no other validation errors are reported for that xsd file and the validation moves on to the next included xsd).
My code is pretty much lifted straight from the Microsoft documentation:
public XsdValidationResult ValidateXml(string filePath)
{
var schemas = GetSchemas();
var settings = new XmlReaderSettings();
settings.Schemas.Add(schemas);
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationEventHandler += XsdValidationEventHandler;
using var reader = XmlReader.Create(filePath, settings);
var doc = new XmlDocument
{
PreserveWhitespace = true
};
doc.Load(reader);
return GetValidationResult();
}
private void XsdValidationEventHandler(object sender, ValidationEventArgs e)
{
if (e.Severity != XmlSeverityType.Error) return;
var sb = new StringBuilder();
sb.Append(e.Message);
sb.Append($" Line Number: {e.Exception.LineNumber}");
sb.Append($" Position: {e.Exception.LinePosition}");
_errors.Add(sb.ToString());
}
The validation error I get looks something like this (before moving on to the next schema):
The element 'subSchema.elementGroup' in namespace 'namespace' has
invalid child element 'subSchema.element02' in namespace 'namespace'.
List of possible elements expected: 'subSchema.element03' in namespace
'namespace'.
I did come across this possible explanation of what is happening in the Microsoft docs:
When the new XmlReader has been closed, the original XmlReader will be
positioned on the EndElement node of the sub-tree. Thus, if you called
the ReadSubtree method on the start tag of the book element, after the
sub-tree has been read and the new XmlReader has been closed, the
original XmlReader is positioned on the end tag of the book element.
but this behaviour is different from what I need :(
Ultimately my question is, is there a way to continue parsing the XML file after an element has been discovered as missing (either using a different library or through the included .NET library) so as to capture all XSD validation errors?

XSD2Code classes require duplicate-named element containing collection of elements

Given XSD like:
<xs:complexType name="accident">
<xs:sequence>
<xs:element name="NAME" type="xs:string" />
<xs:element name="DESCRIPTION" type="xs:string" />
<xs:element name="CREATIONDATE" type="xs:dateTime" />
</xs:sequence>
</xs:complexType>
<xs:element name="accidents">
<xs:complexType>
<xs:sequence>
<xs:element name="accident" type="accident" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
I expect XML like:
<?xml version="1.0" encoding="UTF-8"?>
<accidents>
<accident>
<NAME>Accident 123</NAME>
<DESCRIPTION>Car crash</DESCRIPTION>
<CREATIONDATE>2016-01-20T12:08:00+00:00</CREATIONDATE>
</accident>
</accidents>
I used XSD2Code to generate C# classes so I can easy deserialize XML from a web-service. But they weren't working right - they were successfully loading a test XML like my example but there were zero accident elements.
So I decided to reverse the process:
accidents aa = new accidents();
accident a = new accident();
a.NAME = "test";
aa.accident.Add(a);
aa.SaveToFile("accidents.xml");
This emitted the following XML:
<?xml version="1.0"?>
<accidents xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<accident>
<accident>
<NAME>test</NAME>
<CREATIONDATE>0001-01-01T00:00:00</CREATIONDATE>
</accident>
</accident>
</accidents>
If I attempt to deserialize that XML, it works just fine. But note, there is a nested accident which is not correct and I have no idea it would do this or what to do to fix it!
This seems to be a similar question but since it didn't get much attention and the XSD isn't included, I'm not sure: xsd2code creates extra nested collection when serializing lists
I'm a bit late on the scene for this one but here goes anyway !!
I have been using Xsd2Code myself for a while to take advantage of some cool features, but I have found it does have some annoying quirks. I agree that this issue you describe looks like a bug. However I have found that the issue disappears if your collection is itself a child element of another complex type. If you are happy for your "accidents" to exist as a property of a "report" for example, then you would alter your schema as follows:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:complexType name="accident">
<xs:sequence>
<xs:element name="NAME" type="xs:string" />
<xs:element name="DESCRIPTION" type="xs:string" />
<xs:element name="CREATIONDATE" type="xs:dateTime" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="accidents">
<xs:sequence>
<xs:element name="accident" type="accident" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="report">
<xs:sequence>
<xs:element name="accidents" type="accidents"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
When you run this through the Xsd2Code tool you will find that the
generated code creates the accidents property of report type as a list of accidents and will serialize in the way you would expect it.
Your test code should look more like this:
report r = new report();
r.accidents = new List<accident>();
accident a = new accident();
a.NAME = "test";
r.accidents.Add(a);
r.SaveToFile("accidents.xml");
The dodgy accidents class is still generated unfortunately - which could cause confusion to other developers, but there is a way to prevent this.
First, put the accident and accidents complexType definitions in a
file, accidents.xsd. Then put the report definition in report.xsd with
an include statement referencing accidents.xsd. Only pass report.xsd
through the Xsd2Code tool. The malformed accidents class will not appear in the generated code. This is just an illustrative example of course - expand as required. In the absence of a fix, this has been a very good solution for me - hopefully it will suit your needs.
You might start by specifying a target namespace and explicit qualification flags in your XSD. That is, convert your xsd to:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.com/foo"
xmlns="http://example.com/foo">
<xs:complexType name="accident">
<xs:sequence>
<xs:element name="NAME" type="xs:string" />
<xs:element name="DESCRIPTION" type="xs:string" />
<xs:element name="CREATIONDATE" type="xs:dateTime" />
</xs:sequence>
</xs:complexType>
<xs:element name="accidents">
<xs:complexType>
<xs:sequence>
<xs:element name="accident" type="accident" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
and your XML to:
<?xml version="1.0" encoding="UTF-8"?>
<accidents xmlns="http://example.com/foo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://example.com/foo foo.xsd">
<accident>
<NAME>Accident 123</NAME>
<DESCRIPTION>Car crash</DESCRIPTION>
<CREATIONDATE>2016-01-20T12:08:00+00:00</CREATIONDATE>
</accident>
</accidents>
(You will need to save your xsd file as foo.exe for the above reference to work).
I'm not sure if this will fix your XSD2Code issue, but I've used this header format with xsd.exe for lots of equivalent (and much more complex) code. It gets you Intellisense in your XML and might also be sufficient to get XSD2Code to behave properly.

How do you create an XML document from an XSD Schema at runtime in modern c#? [duplicate]

I have searched for a bit now, but i'm not able to find a way to autogenerate data from a XML Schema programmatically. Lets say I have this XML schema:
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" name ="Persons">
<xs:complexType>
<xs:sequence>
<xs:element name="Person">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName" type="xs:string" />
<xs:element name="LastName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
I am able to create a XML from this using the VS function "Generate Sample XML"
Is there a way to do this programmatically?
Edit: To specify. I do not want to create all the objects and insert data programmatically myself. I would like for it to create the objects and attributes automatically just like the "Generate Sample XML" in VS. The reason for this is that i would like to change the XSD without having to do anything about xml sample generation.
after doing some searching. I have found a project that have implemented a xml sample generator. I created a test solution and imported the classes. Then i deleted the XmlGen.cs file and created my own main method. The output will be based on the root element.
public static void Main(string[] args)
{
using (var stream = new MemoryStream(File.ReadAllBytes("schema.xsd")))
{
var schema = XmlSchema.Read(XmlReader.Create(stream ), null);
var gen = new XmlSampleGenerator(schema, new XmlQualifiedName("rootElement"));
gen.WriteXml(XmlWriter.Create(#"c:\temp\autogen.xml"));
Console.WriteLine("Autogenerated file is here : c:\temp\autogen.xml");
}
}
You can write simple function for put 1 row into your data table and after that execute DataTable.WriteXml(string filePath)
Somethig like that:
xmlschema1 schema=new xmlschema1();
//put some test data in table
schema.Persons.AddPersonsRow(...some params);
//generate xml
schema.Persons.WriteXml(filePath);

Generate a test XML from XML Schema programmatically

I have searched for a bit now, but i'm not able to find a way to autogenerate data from a XML Schema programmatically. Lets say I have this XML schema:
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" name ="Persons">
<xs:complexType>
<xs:sequence>
<xs:element name="Person">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName" type="xs:string" />
<xs:element name="LastName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
I am able to create a XML from this using the VS function "Generate Sample XML"
Is there a way to do this programmatically?
Edit: To specify. I do not want to create all the objects and insert data programmatically myself. I would like for it to create the objects and attributes automatically just like the "Generate Sample XML" in VS. The reason for this is that i would like to change the XSD without having to do anything about xml sample generation.
after doing some searching. I have found a project that have implemented a xml sample generator. I created a test solution and imported the classes. Then i deleted the XmlGen.cs file and created my own main method. The output will be based on the root element.
public static void Main(string[] args)
{
using (var stream = new MemoryStream(File.ReadAllBytes("schema.xsd")))
{
var schema = XmlSchema.Read(XmlReader.Create(stream ), null);
var gen = new XmlSampleGenerator(schema, new XmlQualifiedName("rootElement"));
gen.WriteXml(XmlWriter.Create(#"c:\temp\autogen.xml"));
Console.WriteLine("Autogenerated file is here : c:\temp\autogen.xml");
}
}
You can write simple function for put 1 row into your data table and after that execute DataTable.WriteXml(string filePath)
Somethig like that:
xmlschema1 schema=new xmlschema1();
//put some test data in table
schema.Persons.AddPersonsRow(...some params);
//generate xml
schema.Persons.WriteXml(filePath);

NDBUnit schema error

I've been searching for an answer for quite some time without any luck.
I'm using NDbUnit for my test data and I want to be able to generate my XSD files automatically. I don't want to have to regenerate my XSD files each time I add a new property to my classes. So my plan is to automatically generate the XSD files using the XsdDataContractExporter class since some of my classes contain IList and I got some errors using the xml serializer.
this is the code I got so far:
XsdDataContractExporter exporter = new XsdDataContractExporter();
exporter.Export(typeof(Supplier));
//XmlQualifiedName xmlQualifiedName = exporter.GetRootElementName(typeof(Supplier));
foreach (XmlSchema schema in exporter.Schemas.Schemas()) {
XmlWriter writer = XmlWriter.Create(String.Format(#"..\..\data\{0}.xsd", GetSchemaName(schema)), new XmlWriterSettings() {
ConformanceLevel = ConformanceLevel.Auto,
Encoding = Encoding.UTF8,
Indent = true,
OmitXmlDeclaration = false
});
foreach (XmlSchemaObject include in schema.Includes) {
XmlSchemaImport importedSchema = include as XmlSchemaImport;
if (importedSchema != null) {
ArrayList lst = new ArrayList(exporter.Schemas.Schemas(importedSchema.Namespace));
XmlSchema actualImportedSchema = (XmlSchema)lst[0];
importedSchema.Schema = actualImportedSchema;
importedSchema.SchemaLocation = Path.GetFullPath(String.Format(#"..\..\data\{0}.xsd", GetSchemaName(actualImportedSchema)));
}
}
schema.Write(writer);
writer.Close();
}
DataSet ds = new DataSet();
ds.ReadXmlSchema(#"..\..\data\business.model.supplier.xsd");
the problem is that I get an error when reading the schema which is:
failed: System.InvalidOperationException : Nested table 'SupplierCategory' which inherits its namespace cannot have multiple parent tables in different namespaces.
The bottom line is, I want to use a dynamically generated XSD file from a type to use with NDBUnit to populate my database with test data. Is this the right approach ? This is the schema that are generated and that gives my the error:
Supplier:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://schemas.datacontract.org/2004/07/Business.Model.Supplier" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/Business.Model.Supplier" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import schemaLocation="C:\dev\skeleton\branches\dev\src\testconsole\data\business.model.supplier.category.xsd" namespace="http://schemas.datacontract.org/2004/07/Business.Model.Supplier.Category" />
<xs:import schemaLocation="C:\dev\skeleton\branches\dev\src\testconsole\data\arrays.xsd" namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
<xs:complexType name="Supplier">
<xs:sequence>
<xs:element minOccurs="0" name="Categories" nillable="true" xmlns:q1="http://schemas.datacontract.org/2004/07/Business.Model.Supplier.Category" type="q1:ArrayOfSupplierCategory" />
<xs:element minOccurs="0" name="Comments" nillable="true" xmlns:q2="http://schemas.microsoft.com/2003/10/Serialization/Arrays" type="q2:ArrayOfstring" />
<xs:element minOccurs="0" name="Description" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="Name" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="Supplier" nillable="true" type="tns:Supplier" />
</xs:schema>
SupplierCategory:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://schemas.datacontract.org/2004/07/Business.Model.Supplier.Category" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/Business.Model.Supplier.Category" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="ArrayOfSupplierCategory">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="SupplierCategory" nillable="true" type="tns:SupplierCategory" />
</xs:sequence>
</xs:complexType>
<xs:element name="ArrayOfSupplierCategory" nillable="true" type="tns:ArrayOfSupplierCategory" />
<xs:complexType name="SupplierCategory">
<xs:sequence>
<xs:element minOccurs="0" name="Description" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="SupplierCategory" nillable="true" type="tns:SupplierCategory" />
</xs:schema>
Any advice would be great !
Thx,
Franck
See the list of suggestions in this post Getting XML Schema from MS SQL Database (specifically the top-voted answer) but also note my suggestion of using MyGeneration to achieve the same thing.
That's a problem I've also been facing quite a time later, as we were using NDbUnit for integration tests in our project – ended up with a custom library, which doesn't need a schema to be defined separately, it reads it from database on its own. Library is Reseed.

Categories