How to do simple XML schema validation with no namespaces in C# - c#

I have generated a set of classes using xsd.exe and created an XML document from the resulting generated code. I would now like to validate the serialized class instance against the original xsd.
My XML is like this:
<?xml version="1.0" encoding="UTF-8"?>
<MyRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-- rest of XML document here
</MyRoot>
My XSD is like this:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="MyRoot" type="MyRootType"/>
-- MyRootType definition and rest of XSD
</xs:schema>
When I try to validate the XML using a XmlReader, I get the following error:
"The 'MyRoot' element is not declared."
What could be wrong?

In your MyRoot element, you need to add the location of the XSD. I would also recommend defining the namespace (unless you have good reason not to).
<api:MyRoot xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:api='http://www.myserver.com/schema'
xsi:schemaLocation='http://www.myserver.com/schema http://www.myserver.com/schema/websuiterecord.xsd'>
</api:MyRoot>
This way, the validation tool knows where to find your XSD to validate your XML against.

The approach was correct, but the XSD was not infact being read. I corrected this and it worked as expected.

Related

Deserialize XML having Multiple xsi:type attributes

I am working on deserializing XML file where a same class has different namespaces. I am getting error while The specified type was not recognized. Here is a snippet from the XML I am trying to parse
<BookingHistory xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="dbpnr" xsi:type="ns3:SegmentHistory" Segment="ID13" eventDate="2014-04-03" eventTime="05:29:00" actionType="Change"/>
<BookingHistory xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="dbpnr" xsi:type="ns3:SsrHistory" eventDate="2014-04-03" eventTime="14:06:00" actionType="Add">
<BookingHistory xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="dbpnr" xsi:type="ns3:RemarkHistory" eventDate="2014-04-03" eventTime="15:02:00" actionType="Add">
Here is the sample XML
https://drive.google.com/file/d/1RDOAGa2TECSIauSHkdYTuSNuTWx5GVb8/view
Any suggestions would be highly appreciated.

Ignoring namespaces in XML deserialize

I want to deserialize XML into object. I have no controll what xml i'm reciving, and into what object I'm deserializing.
I tried this: Can I make XmlSerializer ignore the namespace on deserialization? and it worked... almost.
my xml
<request xmlns:a="http://schemas.datacontract.org/2004/07/My.Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">
<a:ProfileInfo i:type="a:ProfileAndBSymbol">
<a:BSymbol>_47</a:BSymbol>
<a:ProfileSymbol>FAJNY</a:ProfileSymbol>
</a:ProfileInfo>
</request>
a:ProfileInfo works fine, but i:type thrown an exception. How to ignore i:?
exception is in Polish and it is like this:
InvalidOperationException: type is invalid. name= ProfileAndBSymbol,
namespace=http://schemas.datacontract.org/2004/07/My.Contracts

How do I get multiple namespaces in XML C#?

Following is the XML format:
<?xml version="1.0" encoding="UTF-8"?>
<package version="2.0" unique-identifier="isbn0000000000000" xmlns="http://www.idpf.org/2007/opf">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:title>Eltern Family</dc:title>
<dc:creator></dc:creator>
<dc:publisher></dc:publisher>
<dc:rights></dc:rights>
<dc:identifier id="isbn0000000000000">0000000000000</dc:identifier>
<dc:language>de</dc:language>
<dc:date opf:event="publication">2019-02-11</dc:date>
</metadata>
</package>
Here I got the default Namespace by XDocument.Root.GetDefaultNamespace();. But as you can see, there are multiple namespaces in the <metadata> XML node. The problem is that, they are variable i.e., each XML may have different values, so I cannot declare a variable with one fixed value.
How do I get the namespaces, so that I can add values to the descendant elements?
Please help.
Regards
Aman
If, as you say, you want to set the content of dc:rights, then you need to get hold of that element.
You can do this by name - the 'qualified name' is made of of the namespace and a local name. The namespace prefix dc is not actually important in and of itself, it's just used as a shorthand to refer to the namespace within the document.
Assuming you have parsed this XML to an XDocument called doc:
XNamespace dc = "http://purl.org/dc/elements/1.1/"
var rights = doc.Descendants(dc + "rights").Single();
rights.Value = "text";

Error using "Xlmns" in XML document

I want to generate below code snippet into xml with c#:
<?xml version="1.0" encoding="utf-8" ?>
<PrincetonStorageRequest
xmlns="http://munichre.com/eai/dss/pct/v1.0"
requestId="RequestOut_MAG_Test_02"
timestampUtc="2015-02-19T09:25:30.7138903Z">
<StorageItems>
and my code is :
XmlWriter writer = XmlWriter.Create(fileName);
writer.WriteStartDocument(true);
writer.WriteStartElement("PrincetonStorageRequest");
writer.WriteAttributeString("xmlns","http://example.com/abc/dss/pct/v1.0");
writer.WriteAttributeString("requestId",name);
writer.WriteAttributeString("timestampUtc","2015-02-19T09:25:30.7138903Z");
writer.WriteStartElement("StorageItems");
But I am getting
"The prefix " cannot be redefined from " to within the same start element tag.
From your XML and the error, I believe it's because you are adding a default namespace after adding an element with no namespace declaration, so you're effectively creating an element and then changing its namespace.
Try the following code - it stops the error when I test it locally just for the XML I think you're trying to get:
XmlWriter writer = XmlWriter.Create(fileName);
writer.WriteStartDocument(true);
writer.WriteStartElement("PrincetonStorageRequest", "http://example.com/abc/dss/pct/v1.0");
writer.WriteAttributeString("xmlns", "http://example.com/abc/dss/pct/v1.0");
writer.WriteAttributeString("requestId", name);
writer.WriteAttributeString("timestampUtc", "2015-02-19T09:25:30.7138903Z");
writer.WriteStartElement("StorageItems");
So when I create the PrincetonStorageRequest element I am specifying a namespace URI.
Edit: Just to check, this is the XML that gets created but I did have to add the code to write the end elements:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<PrincetonStorageRequest xmlns="http://example.com/abc/dss/pct/v1.0" requestId="RequestOut_MAG_Test_02" timestampUtc="2015-02-19T09:25:30.7138903Z">
<StorageItems/>

Validate XML nodes against a schema using accesory XSD files

I need to create XML file compliant to a complex XSD file. My approach is to validate step by step (using TDD) every type on the XSD. I can only validate root elements, so what I am doing is
Create a new schema, on the same namespace, with only a root element called "TestNode" of the target complex type to test
Add the schema to the schema validation list
So, this a part of the original complex schema
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns="urn:FooSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="urn:FooSchema">
<xs:element name="Document" type="Document"/>
<xs:complexType name="AComplexType">
<xs:sequence>
<xs:element name="MsgId" type="Max35Text"/>
...
</xs:complexType>
...
...
<xs:element name="OriginalElement" type="AComplexType"/>
...
...
</xs:schema>
I want to create and validate XML nodes with "AComplexTypeFormat" format, but I can't validate 'OriginalElement' because it's not a root element.
I am not allowed to modify the original XSD file. Thus, my workaround is create an accesory NodeTester XSD file:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element xmlns="urn:FooSchema" name="TestNode" type="AComplexType" />
</xs:schema>
And then add BOTH schemas to the validation list
XmlSchema originalSchema = XmlSchema.Read(new StreamReader("ComplexSchema.xsd"), XMLValidationEventHandler);
XmlSchema testingSchema = XmlSchema.Read(new StreamReader("NodeTester.xsd"), XMLValidationEventHandler);
XmlReaderSettings validatorSettings = new XmlReaderSettings();
validatorSettings.Schemas.Add(originalSchema);
validatorSettings.Schemas.Add(testingSchema);
validatorSettings.ValidationType = ValidationType.Schema;
validatorSettings.ConformanceLevel = ConformanceLevel.Fragment;
validatorSettings.ValidationEventHandler += new ValidationEventHandler(XMLValidationEventHandler);
XmlReader validationReader = XmlReader.Create(new StringReader(stringXML), validatorSettings);
while (validationReader.Read()) { }
When I validate the stringXML that contains the XML node, I receive an error (sorry, translating from spanish):
The element 'TestNode' has a secondary element 'MsgId' not valid. Expected list of possible elements: 'MsgId' in the namespace 'urn:FooSchema'.
Cryptic :( 'MsgID' is not allowed because the validator is waiting for... 'MsgID'
What is wrong? Is this correct (adding another scheme to list), or there is another way to merge elements of the same namespace coming from different files to make a validation?
Thanks!
Finally, I have found another workaround: not add new schemas, but EDIT THE SCHEME
So, If I need to test if a XML fragment(node) is compilant to a particular XSD type, I just edit the schema and add a ROOT element of the type to test, with the name of the XML fragment root element.
public static void AddElementToSchema(XmlSchema xmlSchema, string elementName, string elementType, string xmlNamespace)
{
XmlSchemaElement testNode = new XmlSchemaElement();
testNode.Name = elementName;
testNode.Namespaces.Add("", xmlNamespace);
testNode.SchemaTypeName = new XmlQualifiedName(elementType, xmlNamespace);
xmlSchema.Items.Add(testNode);
xmlSchema.Compile(XMLValidationEventHandler);
}
In my new, compiled in memory schema, the element is now root and I can validate it correctly :)

Categories

Resources