Xml Xsd Validation Fails (xs:anyType) - c#

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.

Related

Error while validating XML

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;
}
}
}
}
}
}

XML Signature element is not declared

I created XSD using Visual StudioXML Tools. And I use following C# code to validate XML and facing this error.
Error
The element is not declared
'http://www.w3.org/2000/09/xmldsig#:Signature'.
So my question is how to fix it because in edit mode XML is valid 100%?
Thank you!
C#
private void buttonValidateXML_Click(object sender, EventArgs e)
{
try
{
bool result = IsValidXml2(textBoxSignedXML.Text, textBoxXSDFile.Text, "");
rtbValidationResult.Text = result.ToString();
}
catch (Exception ex)
{
rtbValidationResult.Text = ex.Message;
}
}
public static bool IsValidXml2(string xmlFilePath, string xsdFilePath, string namespaceName)
{
var xdoc = XDocument.Load(xmlFilePath);
var schemas = new XmlSchemaSet();
schemas.Add(namespaceName, xsdFilePath);
bool result = true;
xdoc.Validate(schemas, (sender, e) =>
{
result = false;
});
return result;
}
XML
<?xml version="1.0" encoding="utf-8"?>
<Envelope version="1">
<Deposit>
<ClientId>1234567890123</ClientId>
<Account>0045678</Account>
<Currency>USD</Currency>
<Total>5000.00</Total>
<SignedDate>2016-02-15</SignedDate>
<Cheques>
<Cheque>
<Images>
<Front>
SUkqAAgAAAAPAP4ABAABAAAAAAAAAAABBAABAAAAfQUAAAEBBAABAAAAWgIAAAIBAwABAAAAAQAA
AAMBAwABAAAABAAAAAYBAwABAAAAAAAAAA4BAgAhAAAA0AAAABEBBAABAAAAAAIAABIBAwABAAAA
AQAAABUBAwABAAAAAQAAABYBBAABAAAAWgIAABcBBAABAAAAvi8AABoBBQABAAAAAAEAABsBBQAB
EdF0fRG0R0YRdH2R2XzaI6OxRQAQAQA=
</Front>
<Back>
SUkqAAgAAAAOAP4ABAABAAAAAAAAAAABBAABAAAAgQUAAAEBBAABAAAAVAIAAAIBAwABAAAAAQAA
AAMBAwABAAAABAAAAAYBAwABAAAAAAAAABEBBAABAAAAAAEAABIBAwABAAAAAQAAABUBAwABAAAA
AQAAABYBBAABAAAAVAIAABcBBAABAAAAcggAABoBBQABAAAAwAAAABsBBQABAAAA0AAAACgBAwAB
AAAAAgAAAAAAAAAAAAAAAAAAAAAAyAAAAAEAAAAAAAAAAAAAAMgAAAABAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//LZCdO1f7iRrKXTqt//pePx///9lNoL487Ajh
jFyzUrtwg+6gg9VmvCIWA42XMwziSUEEw7GoIcSUWZ3Y0oKmGR3LToGVC2LhkK6H4sorQNRUMLjH
LTGzlpv3RFCcH4NLB9hvLTmD8tMgOsG+WVaR5AweTcEWMMfaDQxDIx5NwVQx8OMPeGFHLSUlLcSS
1JtNV/9/rrffuO+h9bx////kfvABABAA
</Back>
</Images>
<MicrCodeCmc>123456789012345678901234567890</MicrCodeCmc>
<Amount>465.22</Amount>
<PaymentDate>2016-02-15</PaymentDate>
<EmissionDate>2016-02-15</EmissionDate>
</Cheque>
<Cheque>
<Images>
<Front>
SUkqAAgAAAAPAP4ABAABAAAAAAAAAAABBAABAAAAfQUAAAEBBAABAAAAWgIAAAIBAwABAAAAAQAA
AAMBAwABAAAABAAAAAYBAwABAAAAAAAAAA4BAgAhAAAA0AAAABEBBAABAAAAAAIAABIBAwABAAAA
AQAAABUBAwABAAAAAQAAABYBBAABAAAAWgIAABcBBAABAAAAvi8AABoBBQABAAAAAAEAABsBBQAB
EdF0fRG0R0YRdH2R2XzaI6OxRQAQAQA=
</Front>
<Back>
SUkqAAgAAAAOAP4ABAABAAAAAAAAAAABBAABAAAAgQUAAAEBBAABAAAAVAIAAAIBAwABAAAAAQAA
AAMBAwABAAAABAAAAAYBAwABAAAAAAAAABEBBAABAAAAAAEAABIBAwABAAAAAQAAABUBAwABAAAA
AQAAABYBBAABAAAAVAIAABcBBAABAAAAcggAABoBBQABAAAAwAAAABsBBQABAAAA0AAAACgBAwAB
AAAAAgAAAAAAAAAAAAAAAAAAAAAAyAAAAAEAAAAAAAAAAAAAAMgAAAABAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//LZCdO1f7iRrKXTqt//pePx///9lNoL487Ajh
jFyzUrtwg+6gg9VmvCIWA42XMwziSUEEw7GoIcSUWZ3Y0oKmGR3LToGVC2LhkK6H4sorQNRUMLjH
LTGzlpv3RFCcH4NLB9hvLTmD8tMgOsG+WVaR5AweTcEWMMfaDQxDIx5NwVQx8OMPeGFHLSUlLcSS
1JtNV/9/rrffuO+h9bx////kfvABABAA
</Back>
</Images>
<MicrCodeCmc>123456789012345678901234567890</MicrCodeCmc>
<Amount>99999999999</Amount>
<PaymentDate>2016-02-15</PaymentDate>
<EmissionDate>2016-02-15</EmissionDate>
</Cheque>
</Cheques>
</Deposit>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>TVO2Gssf5TUdXFYG/PrHDyqYFqs=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>KwQInN03ywa0u0t4HedxgE1fOU7XYLQScKuQ6vdYoIZME5Hm5jpFeX2ORA2U+BO7JNjmFilTW05VntS3k98YCZhNXH9Iw/YEC1nw4JJLzygYbbCftkiY5v5+b494mQPryCtscwTtbziW6QilILSFDGmco2JopRfVe+qfdN/JyB1HXhUfApyNEsw/cJLj6aaz5ivN1sLFgAlikbwCNpF+mRnZY5u7/S8uT8WhEyK32EcatdjzKbP0PwnIlumhOpUMerWeLZ7neuJq6R/IuFgZ1Y5U6ppyuOjhtiHp4glC/uNUS/y7jMzG29thWBkEtSE9AcEt2IZ0HOEZE3kdFXufjA==</SignatureValue>
</Signature>
</Envelope>
XSD
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.com/ct-required"
xmlns:xmime="http://www.w3.org/2005/05/xmlmime" >
<xs:import namespace="http://www.w3.org/2005/05/xmlmime"
schemaLocation="http://www.w3.org/2005/05/xmlmime"/>
<xs:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="xmldsig-core-schema.xsd"/>
<xs:simpleType name="PNGPictureType"
xmime:expectedContentTypes="image/png">
<xs:restriction base="xs:base64Binary"/>
</xs:simpleType>
<xs:simpleType name="Money">
<xs:restriction base="xs:decimal">
<xs:totalDigits value="13" />
<xs:fractionDigits value="2" />
<xs:minInclusive value="0.00" />
<xs:maxInclusive value="99999999999.99" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="Currency">
<xs:annotation>
<xs:documentation>Currency Code: ISO 4217</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="USD" />
<xs:enumeration value="UYU" />
<xs:minLength value="3" />
<xs:maxLength value="3" />
</xs:restriction>
</xs:simpleType>
<xs:element name="Envelope">
<xs:complexType>
<xs:sequence>
<xs:element name="Deposit" minOccurs="1" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="ClientId" type="xs:unsignedLong" />
<xs:element name="Account" type="xs:unsignedLong" />
<xs:element name="Currency" type="Currency" />
<xs:element name="Total" type="Money" />
<xs:element name="SignedDate" type="xs:date" />
<xs:element name="Cheques">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Cheque">
<xs:complexType>
<xs:sequence>
<xs:element name="Images">
<xs:complexType>
<xs:sequence>
<xs:element name="Front" type="PNGPictureType" />
<xs:element name="Back" type="PNGPictureType" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="MicrCodeCmc" type="xs:string" />
<xs:element name="Amount" type="Money" />
<xs:element name="PaymentDate" type="xs:date" />
<xs:element name="EmissionDate" type="xs:date" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element xmlns:q1="http://www.w3.org/2000/09/xmldsig#" ref="q1:Signature" />
</xs:sequence>
<xs:attribute name="version" type="xs:unsignedByte" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>
UPDATE #1
I have tried different approaches but no joy.
And even if I reference XSD to local file it does not work. I see the same error.
<xs:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212 file:///C:/Temp/xmldsig-core-schema.xsd"/>
UPDATE #2
Even I use this approach no joy.
public static bool IsValidXml1(string xmlFilePath, string xsdFilePath, string namespaceName)
{
XDocument xdoc = null;
var settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Ignore;
settings.ProhibitDtd = false;
try
{
using (XmlReader xr = XmlReader.Create(xmlFilePath, settings))
{
xdoc = XDocument.Load(xr);
var schemas = new XmlSchemaSet();
schemas.Add(namespaceName, xsdFilePath);
schemas.Add(#"http://www.w3.org/2000/09/xmldsig#", #"D:\Temp\xmldsig-core-schema.xsd");
xdoc.Validate(schemas, null);
return true;
}
}
catch (XmlSchemaValidationException ex)
{
// throw;
}
return false;
}
If you don't want to change anything to xsd or xml - do the following:
(optional) Download xsd from w3 site and save to local disk. W3 site is VERY slow because a lot of software worldwide constantly request those schemas. If you will use that xsd directly - you will often fail by timeout. Some validation tools already have such schemas cached locally, but not .NET validator.
Modify your validation method from UPDATE 2 the following way:
public static bool IsValidXml1(string xmlFilePath, string xsdFilePath, string namespaceName)
{
XDocument xdoc = null;
var settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Ignore;
try
{
using (XmlReader xr = XmlReader.Create(xmlFilePath, settings))
{
xdoc = XDocument.Load(xr);
var schemas = new XmlSchemaSet();
schemas.Add(namespaceName, xsdFilePath);
using (var fs = File.OpenRead(#"D:\Temp\xmldsig-core-schema.xsd"))
using (var reader = XmlReader.Create(fs, new XmlReaderSettings() {
DtdProcessing = DtdProcessing.Ignore // important
})) {
schemas.Add(#"http://www.w3.org/2000/09/xmldsig#", reader);
}
xdoc.Validate(schemas, null);
return true;
}
}
catch (XmlSchemaValidationException ex)
{
// throw;
}
return false;
}
You have to add that schema using XmlReader and not directly, because if you add directly (like in your update 2) - it will fail to parse DTD block, because when you add XmlSchema to XmlSchemaSet using url (or file path) - it will read that file using XmlReaderSettings with DtdProcessing = DtdProcessing.Prohibit. We need to change that to DtdProcessing.Ignore or DtdProcessing.Parse. After that your validation method will work fine for target xsd and xml file, without any changes (and will correctly fail in case xml does not match xsd).
You are very close. In your XSD, simply replace,
<xs:import namespace="http://www.w3.org/2000/09/xmldsig#" />
with
<xs:import namespace="http://www.w3.org/2000/09/xmldsig#"
schemaLocation=
"http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"/>
and your XSD will no longer have that error, and your XML will be valid against your XSD.
Explanation
XSDs can be composed via xs:import and xs:include. In both cases, the location of the referenced XSD has to be specified with a required schemaLocation attribute, which was missing in OP's original XSD. By adding xs:import/#schemaLocation as shown above, the error is eliminated.
Update #1:
When you switched to use a local XSD, you made a mistake in your xs:import:
Change
<xs:import namespace="http://www.w3.org/2000/09/xmldsig#"
schemaLocation="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212
file:///C:/Temp/xmldsig-core-schema.xsd"/>
to
<xs:import namespace="http://www.w3.org/2000/09/xmldsig#"
schemaLocation="file:///C:/Temp/xmldsig-core-schema.xsd"/>
(You were following an example for #xsi:schemaLocation in XML documents which has namespace-location pairs; xs:import/#schemaLocation is different.)
Update #2:
So my question is how to fix it because in edit mode XML is valid 100%?
Perhaps this is the disconnect. Editing an XML file in Visual Studio does not automatically validate it against an XSD. You need to do that in code or via a validating XML editor such Oxygen XML Editor or XML Spy.
Also, your C# validation code may have issues. See Validating an XML against referenced XSD in C#

XML Validation error: The element is not declared

I am building a web service in .NET that will pass data back and forth via XML. I would like to validate the XML in the incoming requests using an XSD that I have defined.
Here is the XSD:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="POSearch">
<xs:sequence minOccurs="0" maxOccurs="10">
<xs:element name="POID" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Here is the XML:
<POSearch>
<POID>1</POID>
<POID>2</POID>
</POSearch>
Here is the validation code in C#:
static void Main(string[] args){
XmlSchemaSet iSchemas = new XmlSchemaSet();
iSchemas.Add(string.Empty, #"...xsd file location");
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
settings.Schemas.Add(iSchemas);
XmlReader reader = XmlReader.Create(#"...xml file location", settings);
try {
while(reader.Read())
;
}
catch(Exception ex) {
Console.WriteLine(ex.Message);
}
}
private static void ValidationCallBack(object sender, ValidationEventArgs args) {
if(args.Severity == XmlSeverityType.Warning)
Console.WriteLine("\tWarning: Matching schema not found. No validation occurred." + args.Message);
else
Console.WriteLine("\tValidation error: " + args.Message);
}
I feel like I had this working before and I'm not completely sure why this isn't working now. Whenever I run this I get the following Exception Message:
Validation error: The 'POSearch' element is not declared.
Have I defined my XSD wrong? Is my validation code wrong? The elements are all clearly there. Any help pointing me in the right direction is greatly appreciated.
You have the type declared but no element declared of that type.
Add an element declaration:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="POSearch" type="POSearch"/>
<xs:complexType name="POSearch">
<xs:sequence minOccurs="0" maxOccurs="10">
<xs:element name="POID" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Try this:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="POSearch">
<xs:sequence minOccurs="0" maxOccurs="10">
<xs:element name="POID" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
<xs:element name="POSearch" type="POSearch"/>
</xs:schema>

Need Help About Using XPathNavigator in C#?

My XML file as below. It mixed schema and normal elements.
<?xml version="1.0" encoding="utf-8"?>
<!-- R1 -->
<ax:root xmlns:ax="http://amecn/software/realtime/ax">
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="EquipmentConstants">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="unbounded" ref="EquipmentConstant" />
</xsd:sequence>
</xsd:complexType>
<xsd:unique name="id">
<xsd:selector xpath=".//EquipmentConstant" />
<xsd:field xpath="#id" />
</xsd:unique>
</xsd:element>
......
......
</xsd:schema>
<EquipmentConstants xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<EquipmentConstant id="0">
<Name>SerialNumber</Name>
<Group>SYSTEM</Group>
<Data>
<Value min="0" max="10000000" scale_factor="0" unit="U_NO_UNITS" permission="NolimitedAndNoChangeable" type="xsd_string" enum="" flag="0">0</Value>
</Data>
<Description>Serial Number</Description>
</EquipmentConstant>
.....
.....
</EquipmentConstants>
</ax:root>
My C# code as below. I want to loop the elements start from (by pass all the content of schema)
<EquipmentConstants xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
XPathDocument doc = new XPathDocument("test.xml");
XPathNavigator navigator = doc.CreateNavigator();
navigator.MoveToRoot(); // <?xml version="1.0" encoding="utf-8"?>
//navigator.MoveToFirstChild(); // <!-- R1 -->
// 1st, I tried to use MoveToChield(), But I failed to move there.
navigator.MoveToChild("EquipmentConstants");
// Then, I also tried to use SelectSingleNode(). But I failed too.
navigator.SelectSingleNode("ax/EquipmentConstants");
while (navigator.MoveToNext())
{
// do something.
}
Could you please give me some suggestion. Thank you.
XPathNavigator navigator = doc.CreateNavigator();
if (navigator == null)
{
return;
}
foreach (XPathNavigator nav in
navigator.Select("/" + "EquipmentConstants" + "/" + "EquipmentConstant"))
{
}
My solution as below.
XPathDocument doc = new XPathDocument("test.xml");
XPathNavigator navigator = doc.CreateNavigator();
navigator.MoveToRoot(); // <?xml version="1.0" encoding="utf-8"?>
navigator.MoveToFirstChild(); // <!-- R1 -->
navigator.MoveToNext(); // <ax:root xmlns:ax="http://amecn/software/realtime/ax">
navigator.MoveToChild("EquipmentConstants", ""); // <EquipmentConstants xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
navigator.MoveToFirstChild(); // <EquipmentConstant id="0">
do
{
// Loop body;
} while (navigator.MoveToNext());

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);
});

Categories

Resources