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.
Related
I have a sample to read a xml schema set for a xml file which contains different namespaces. For this i can get different schema for each namespace as i explained below.
Sample File:
<?xml version="1.0" encoding="utf-8"?>
<data xmlns:d="http://sampleschema/dataservices" xmlns:m="http://sampleschema/dataservices/metadata">
<content>
<m:properties>
<d:CustomerID>ALFKI</d:CustomerID>
<d:CompanyName>Alfreds Futterkiste</d:CompanyName>
</m:properties>
</content>
</data>
Sample Code to get XML Schema Set:
strFileName = #"C:\Sample\Sample.xml";
XmlReader reader = XmlReader.Create(strFileName);
XmlSchemaInference schema = new XmlSchemaInference();
XmlSchemaSet schemaSet = schema.InferSchema(reader);
It gives three different types of schemas while using the above code. But my requirement will be i need a single schema for the entire xml file which contain any number of namespaces in it. I have checked with possibilities of codes in msdn and stack overflow. I can't find any proper solution for this.
The expected schema output will be like below.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="data">
<xs:complexType>
<xs:sequence>
<xs:element name="content">
<xs:complexType>
<xs:sequence>
<xs:element name="m:properties">
<xs:complexType>
<xs:sequence>
<xs:element name="d:CustomerID" type="xs:string"></xs:element>
<xs:element name="d:CompanyName" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="xmlns:d" type="xs:string"></xs:attribute>
<xs:attribute name="xmlns:m" type="xs:string"></xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
Any one can help to achieve this requirement.
Thanks in advance.
Try something like this :
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:m="http://www.w3.org/2001/XMLSchema" xmlns:d="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="data">
<xs:complexType>
<xs:sequence>
<xs:element name="content">
<m:complexType>
<m:sequence>
<m:element name="properties">
<d:complexType>
<d:sequence>
<d:element name="CustomerID" type="xs:string"></d:element>
<d:element name="CompanyName" type="xs:string"></d:element>
</d:sequence>
</d:complexType>
</m:element>
</m:sequence>
</m:complexType>
</xs:element>
</xs:sequence>
<d:attribute name="xmlns_d" type="d:string"></d:attribute>
<m:attribute name="xmlns_m" type="d:string"></m:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
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.
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.
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;
Can you help me in parsing this XAML?
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
EntryPointAssembly="Hello" EntryPointType="Hello.App" RuntimeVersion="4.7.50308.0">
<Deployment.Parts>
<AssemblyPart x:Name="Hello" Source="Hello.dll" />
</Deployment.Parts>
</Deployment>
I have tried XmlDocument, XElement, and XamlReader. None is able to load the XAML and fetch me the values.
Update - Code I tried
var appXaml = ... ; //the XAML string mentioned above
XmlDocument:
var x = new XmlDocument();
x.LoadXml(appXaml);
Also,
//I created XSD from the XAML using xsd.exe
//Placed it in "D:\AppManifest.xsd"
var n = new XmlDocument();
var ss = new XmlSchemaSet();
var s = new XmlSchema() { SourceUri = #"D:\AppManifest.xsd" };
ss.Add(s);
ss.Compile();
n.Schemas.Add(ss);
n.LoadXml(appXaml);
XSD code:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="NewDataSet" targetNamespace="http://schemas.microsoft.com/client/2007/deployment" xmlns:mstns="http://schemas.microsoft.com/client/2007/deployment" xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" attributeFormDefault="qualified" elementFormDefault="qualified" xmlns:app1="http://schemas.microsoft.com/winfx/2006/xaml">
<xs:element name="Deployment">
<xs:complexType>
<xs:sequence>
<xs:element name="Deployment.Parts" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="AssemblyPart" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="Name" msdata:Prefix="x" type="xs:string" />
<xs:attribute name="Source" form="unqualified" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="EntryPointAssembly" form="unqualified" type="xs:string" />
<xs:attribute name="EntryPointType" form="unqualified" type="xs:string" />
<xs:attribute name="RuntimeVersion" form="unqualified" type="xs:string" />
</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="Deployment" />
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
XElement:
var z = XElement.Parse(appXaml);
XamlReader:
var l = XamlReader.Parse(appXaml);
try passing xml to parse.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"D:\OldDesktop\Try\app.xaml");
XElement.Parse(xmlDoc.InnerXml);
or iterate through xmldoc
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"D:\OldDesktop\Try\app.xaml");
foreach (XmlElement xElement in xmlDoc.DocumentElement)
{
//do somthing
}
I found that the XAML content that I read from the file contained BOM.
I BOM is stripped out, the XAML code is parsable.
I use Visual Studio 2010. The "Text Visualizer" in debugging mode did not show any sign of BOM (the XAML string is in UTF8). But when I accidently copied the text from the visualizer and pasted in Notepad++, it showed '?' symbol (BOM, in this case.)
Bah. Weird problems in VS.