NullReferenceException when validating xml with .NET 4.6 - c#

I am testing switching from .NET version 4.5.1 to 4.6 and ran into an NullReferenceExceptionin the xsd validation when using an unique constraint on an optional attribute.
at System.Xml.Schema.KeySequence.ToString()
at System.Xml.Schema.XmlSchemaValidator.EndElementIdentityConstraints(Object typedValue, String stringValue, XmlSchemaDatatype datatype)
at System.Xml.Schema.XmlSchemaValidator.InternalValidateEndElement(XmlSchemaInfo schemaInfo, Object typedValue)
at System.Xml.XsdValidatingReader.ProcessEndElementEvent()
at System.Xml.XsdValidatingReader.ProcessElementEvent()
at System.Xml.XsdValidatingReader.ProcessReaderEvent()
at System.Xml.XsdValidatingReader.Read()
at ConsoleApplication.Program.Main(String[] args)
This is stripped code which runs when targeting v4.5.x but fails with a NullReferenceException when using 4.6. (Tested on Win7 with VS2013 and VS2015). Is this legal in xml? Even if not it should raise some XmlException.
Schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Enumerations">
<xs:complexType>
<xs:sequence>
<xs:element name="Enum" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="id" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:unique name="unique_EnumId_contraint">
<xs:selector xpath="Enum"/>
<xs:field xpath="#id"/>
</xs:unique>
</xs:element>
</xs:schema>
XML:
<?xml version="1.0" encoding="utf-8"?>
<Enumerations>
<Enum />
<Enum />
</Enumerations>
C# code:
var settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.Schemas.Add(null, "enumerations.xsd");
using (var xmlReader = XmlReader.Create("enumerations.xml", settings))
{
while (xmlReader.Read())
{
if (xmlReader.NodeType == XmlNodeType.Element)
{
Console.CursorLeft = xmlReader.Depth * 4;
Console.WriteLine(xmlReader.Name);
}
}
}

I can reproduce this. Looks like a bug to me (<rant>.NET 4.6 has a lot...</rant>). You should report it to Microsoft Connect.
While this is fixed, you can check the source here: http://referencesource.microsoft.com/#System.Xml/System/Xml/Schema/ConstraintStruct.cs,091791a9542f1952
What it tells us is it can be overcome using an AppContext switch, so just add this code before any other and it will work:
AppContext.SetSwitch("Switch.System.Xml.IgnoreEmptyKeySequences", true);
More on this switch is available here: Mitigation: XML Schema Validation - note the sentence: "The impact of this change should be minimal" :-)
PS: I believe you can also change these switches using the proper .config file.

Related

different behavior for Full Framework and .NET Core for xml schema compilation

here is my validation code:
string xsdPath = "base.xsd";
XDocument doc = XDocument.Load(xmlPath);
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("http://some.domain.org", xsdPath);
schemas.Compile();
bool isValid = true;
doc.Validate(schemas, (o, e) => {
res.AddMessage(MessageSeverities.Error, $"{e.Severity}:{e.Message}");
isValid = false;
});
if ( isValid ) {
res.AddMessage(
MessageSeverities.Notice,
$"{formFile.FileName} is valid!");
}
this code runs fine when used in a desktop app (.net 4.6)
the code fails when used in a .net core asp 2.1 controller with the following exception raised by schemas.Compile();:
XmlSchemaException: Type 'http://some.domain.org:tAccountingItemTypes' is not declared.
It seems that related schema files are not loaded in the asp core app. How can I force loading of related schemas ?
the schemas are:
base.xsd
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema
targetNamespace="http://some.domain.org"
xmlns="http://some.domain.org"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:include id="enums" schemaLocation="enums.xsd"/>
<xs:complexType name="tAccountingLines">
<xs:sequence>
<xs:element name="AccountingLine" type ="tAccountingLine"></xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="tAccountingLine">
<xs:sequence>
<xs:element name="AccountingType" type="tAccountingItemTypes"></xs:element>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
enums.xsd
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema
targetNamespace="http://some.domain.org"
xmlns="http://some.domain.org"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:simpleType name="tAccountingItemTypes">
<xs:restriction base="xs:string">
<xs:enumeration value="V1"/>
<xs:enumeration value="V2"/>
<xs:enumeration value="V3"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
I've just tried this, and the reason it doesn't load the included schema is that the resolver it uses to load it is null. This should fix it:
schemas.XmlResolver = new XmlUrlResolver();
I've done a bit of digging and found that this is a known behavioural change between Desktop & Core that is documented here:
If the schema being added imports another schema through external URI, Core does not allow resolving that URI by default while Desktop does. To allow the resolution on Core, the following needs to be called before adding the schema: AppContext.SetSwitch("Switch.System.Xml.AllowDefaultResolver", true);
Obviously, in addition to the switch you can explicitly set a resolver so that you're not using the default.

Compare XML files to determine which is which

Our software spits out a number of xml files and I need to determine which is which. For example, there are three different types of xml file (heavily abbreviated):
"IQ.xml"
<?xml version="1.0" encoding="ISO-8859-1"?>
<Catalog xmlns:dt="urn:schemas-microsoft-com:datatypes">
<Rec>
<ITEM dt:dt="string"></ITEM>
<QTY dt:dt="string"></QTY>
</Rec>
</Catalog>
"IMR.xml"
<?xml version="1.0" encoding="ISO-8859-1"?>
<Catalog xmlns:dt="urn:schemas-microsoft-com:datatypes">
<Rec>
<ITEMS dt:dt="string"></ITEMS>
<MFG dt:dt="string"></MFG>
<ROUTE dt:dt="string"></ROUTE>
</Rec>
</Catalog>
"RP.xml"
<?xml version="1.0" encoding="ISO-8859-1"?>
<Catalog xmlns:dt="urn:schemas-microsoft-com:datatypes">
<Rec>
<REF dt:dt="string"></REF>
<PON dt:dt="string"></PON>
</Rec>
</Catalog>
Anyone of these could be passed out at any time and I need a way to determine where to pass these files to. What is the best way to achieve this? Could a schema be used to test the xml file against the fields and then a result passed back?
My initial thoughts were to test against a schema if it doesn't match the first , move on to the second and so on. This is then hard coded and cannot be changed when different XML file types are later added so I'm not too keen on this. I'm not sure at this stage whether this is even the best approach?
This will be coded in C# so I'm not sure whether there are any inbuilt functions which can help or whether it will have to be custom written.
Has anyone needed to do this before? How did you tackle this?
What I would suggest is to validate the XML file over a schema(like you yourself suggested).
Regarding your problem related to the flexibility of your code to later support other schema's there are many choices but it depends on what you want to do.
For example you can keep all your schema's I an config file, and when you validate a new XML file you can run it programmatically through supported schema's, if there is no match.you can throw an exception(unsupported XML file structure for example).
You might also define statically combinations between certain XML files and certain schema's, which you can later deduce programmatically.
Of course when you want to support new schemas you'll need to change the code... But that's a normal behavior.
To create a fully generic and automated method of handling any kind of XML file and any kind of schema will be difficult and you'll need to probably use some sort of naming convention where you would deduce the associated schema from the name or from some information embedded inside the XML file. This could be done at runtime but even then you'll probably support only a limited number of behaviors and you'll need new code when you want to expand your application.
Use an XmlReader with an XmlReaderSettings which specifies the type of validation to perform and a ValidationEventHandler. This can be wrapped into a method that will give you the schema or schemas against which the XML document was successfully validated.
If you're concerned about new schemas being added in the future, then just store them in a central location like a directory and grab them at runtime. New schemas could simply be dropped into the directory as needed.
void Main()
{
var rootDirectory = #"C:\Testing";
var schemaDirectory = Path.Combine(rootDirectory, "Schemas");
var dataDirectory = Path.Combine(rootDirectory, "Data");
var schemaFiles = new[] {
Path.Combine(schemaDirectory, "IQ.xsd"),
Path.Combine(schemaDirectory, "IMR.xsd"),
Path.Combine(schemaDirectory, "RP.xsd")
};
var dataFiles = new[] {
Path.Combine(dataDirectory, "IQ.xml"),
Path.Combine(dataDirectory, "IMR.xml"),
Path.Combine(dataDirectory, "RP.xml")
};
var results = FindMatchingSchemas(dataFiles[1], schemaFiles).Dump();
Console.WriteLine("Matching schema is: {0}", results.First(r => r.Value));
}
private static Dictionary<string, bool> FindMatchingSchemas(string dataFile, string[] schemaFiles)
{
var results = new Dictionary<string, bool>();
foreach (var schemaFile in schemaFiles)
{
results.Add(schemaFile, true);
// Set the validation settings.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationEventHandler += new ValidationEventHandler((object sender, ValidationEventArgs args) =>
{
// Validation error
results[schemaFile] = false;
});
settings.Schemas.Add(null, schemaFile);
// Create the XmlReader object.
XmlReader reader = XmlReader.Create(dataFile, settings);
// Parse the file.
while (reader.Read());
}
return results;
}
// Output: Matching schema is: C:\Testing\Schemas\IMR.xsd
There is a free website which can generate XSD documents from XML documents. http://www.freeformatter.com/xsd-generator.html
IQ.xsd
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Catalog">
<xs:complexType>
<xs:sequence>
<xs:element name="Rec">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="ITEM"/>
<xs:element type="xs:short" name="QTY"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
IMR.xsd
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Catalog">
<xs:complexType>
<xs:sequence>
<xs:element name="Rec">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:short" name="ITEMS"/>
<xs:element type="xs:string" name="MFG"/>
<xs:element type="xs:string" name="ROUTE"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
RP.xsd
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Catalog">
<xs:complexType>
<xs:sequence>
<xs:element name="Rec">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="REF"/>
<xs:element type="xs:short" name="PON"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Derived from Validating an XML against referenced XSD in C#

Issue with adding a new node in XML

I am trying to add a new node in my XML file, but I get InvalidOperationException due to the current position of the navigator.
This is my XML file:
<?xml version="1.0" encoding="utf-8" ?>
<dictionary xmlns="RecnikSema.xsd">
<sentiments>
<sentiment word="napustiti">-2</sentiment>
</sentiments>
</dictionary>
and schema:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="dictionary">
<xs:complexType>
<xs:sequence>
<xs:element name="sentiments">
<xs:complexType>
<xs:sequence>
<xs:element name="sentiment">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="word"/>
<xs:attribute type="xs:double" name="value"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
The code in C# which I am using to add a new node looks like this:
XmlDocument dictionary= new XmlDocument();
dictionary.Load(#"C:\Users\Luka\Documents\Visual Studio 2013\Projects\TSA\TSA\Dictionary.xml");
XPathNavigator navigator = dictionary.CreateNavigator();
navigator.MoveToChild("dictionary", #"C:\Users\Luka\Documents\Visual Studio 2013\Projects\TSA\TSA\RecnikSema.xsd");
navigator.MoveToChild("sentiments", #"C:\Users\Luka\Documents\Visual Studio 2013\Projects\TSA\TSA\RecnikSema.xsd");
navigator.MoveToChild("sentiment", #"C:\Users\Luka\Documents\Visual Studio 2013\Projects\TSA\TSA\RecnikSema.xsd");
navigator.InsertAfter("<sentiment word=\"" + token + "\">" + value + "</sentiment>");
The exception is occuring on the last line, on InsertAfter.
What am I doing wrong here?
Why don't you make it simple mate by using XDocument.
The new version of C# has got this class that makes it easy to manipulate Xml. Thus, it also supports Xml Linq as well.
Here is the quick solution that may be useful for you.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
XDocument document = XDocument.Load(#"C:\Users\amit\SkyDrive\code\WebApplication1\ConsoleApplication1\xml.xml");
XElement root = new XElement("sentiment");
root.Value = "3";
root.Add(new XAttribute("word", "napustiti"));
XNamespace nsSys = "RecnikSema.xsd";
document.Element(nsSys + "dictionary").Element(nsSys + "sentiments").Add(root);
document.Save("c:\newFile.xml");
}
}
}
I think your problem is that you did not specify the maxOccurs (default is 1) and you allready added on element. See http://www.w3schools.com/schema/el_sequence.asp
maxOccurs Optional. Specifies the maximum number of times the sequence
element can occur in the parent element. The value can be any number>=
0, or if you want to set no limit on the maximum number, use the value
"unbounded". Default value is 1
so your Solution for multiple sentiments:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="dictionary">
<xs:complexType>
<xs:sequence>
<xs:element name="sentiments">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="sentiment">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="word"/>
<xs:attribute type="xs:double" name="value"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
I would prefer using Microsoft xsd tool to generate a CLR Class -> http://msdn.microsoft.com/en-us/library/x6c1kb0s(v=vs.110).aspx and using XMLSerializer -> http://msdn.microsoft.com/de-de/library/system.xml.serialization.xmlserializer(v=vs.110).aspx
In MoveToChild(), the second argument is the XML namespace, not the location of your document. In your case, you have set xmlns="RecnikSema.xsd". This means MoveToChild cannot find a match, so when you get to insertAfter, the current node is still the root node <dictionary>, and it attempts to create XML like this:
<?xml version="1.0" encoding="utf-8" ?>
<dictionary xmlns="RecnikSema.xsd">
<sentiment word="napustiti">-2</sentiment>
</dictionary>
<sentiment word="foo">5</sentiment>
This has 2 root elements and so you get the error
Instead you need to pass "RecnikSema.xsd" as the argument.:
navigator.MoveToChild("dictionary", "RecnikSema.xsd");
navigator.MoveToChild("sentiments", "RecnikSema.xsd");
navigator.MoveToChild("sentiment", "RecnikSema.xsd");
I'm not sure you meant to set this as the namespace as it is the Schema file, so maybe you mean this?:
XML
<?xml version="1.0" encoding="utf-8" ?>
<dictionary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="RecnikSema.xsd">
<sentiments>
<sentiment word="napustiti">-2</sentiment>
</sentiments>
</dictionary>
C#
XmlDocument dictionary= new XmlDocument();
dictionary.Load(#"C:\Users\Luka\Documents\Visual Studio 2013\Projects\TSA\TSA\Dictionary.xml");
XPathNavigator navigator = dictionary.CreateNavigator();
navigator.MoveToChild("dictionary", "");
navigator.MoveToChild("sentiments", "");
navigator.MoveToChild("sentiment", "");
navigator.InsertAfter("<sentiment word=\"" + token + "\">" + value + "</sentiment>");

C# XML not correctly validating against Schema in XmlReaderSettings

I searched and did not find any questions addressing this problem.
I am attempting to validate various XML against a schema and it seems to be validating ALL well-formed XML, instead of just XML that conforms to the schema. I have posted the code I am using, the Schema, a sample valid XML and a sample invalid XML.
I have been struggling with this for awhile. I am in the dark on most of this. I've had to learn how to write an XSD, write the XSD, then learn how to parse XML in C#. None of which I have ever done before. I have used many tutorials and the microsoft website to come up with the following. I think this should work, but it doesn't.
What am I doing wrong?
private bool ValidateXmlAgainstSchema(string sourceXml, string schemaUri)
{
bool validated = false;
try
{
// REF:
// This should create a SCHEMA-VALIDATING XMLREADER
// http://msdn.microsoft.com/en-us/library/w5aahf2a(v=vs.110).aspx
XmlReaderSettings xmlSettings = new XmlReaderSettings();
xmlSettings.Schemas.Add("MySchema.xsd", schemaUri);
xmlSettings.ValidationType = ValidationType.Schema;
xmlSettings.ValidationFlags = XmlSchemaValidationFlags.None;
XmlReader xmlReader = XmlReader.Create(new StringReader(sourceXml), xmlSettings);
// parse the input (not sure this is needed)
while (xmlReader.Read()) ;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlReader);
validated = true;
}
catch (XmlException e)
{
// load or parse error in the XML
validated = false;
}
catch (XmlSchemaValidationException e)
{
// Validation failure in XML
validated = false;
}
catch (Exception e)
{
validated = false;
}
return validated;
}
The XSD / Schema. The intent is to accept XML that contains either an Incident or a PersonOfInterest.
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="MySchema.xsd"
xmlns="MySchema.xsd"
elementFormDefault="qualified"
>
<xs:element name="Incident" type="IncidentType"/>
<xs:element name="PersonOfInterest" type="PersonOfInterestType"/>
<xs:complexType name="IncidentType">
<xs:sequence>
<xs:element name="Description" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="PersonOfInterest" type="PersonOfInterestType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="PersonOfInterestType">
<xs:sequence>
<xs:element name="Name" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Here is a sample of valid XML
<?xml version="1.0" encoding="utf-8" ?>
<Incident
xmlns="MySchema.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3schools.com MySchema.xsd"
>
<Description>something happened</Description>
<PersonOfInterest>
<Name>Joe</Name>
</PersonOfInterest>
<PersonOfInterest>
<Name>Sue</Name>
</PersonOfInterest>
</Incident>
This is a sample of well-formed invalid XML which should throw an exception (I thought), but when I try it, the code returns true, indicating it is valid against the schema.
<ghost>Boo</ghost>
The reason your <ghost>Boo</ghost> validates is that the parser cannot find any schema matching the xml. If there is no schema then the parser assumed validity, providing the xml is well-formed. It's counter-intuitive I know, and will probably differ based on parser implementation.
This notwithstanding, there are several problems with your code:
Two Root Elements
This is a big no-no in xsd - you can only have a single root element. Some parsers will actually throw an exception, others tolerate it but will only use the first root element (in your case Incident) for any subsequent validation.
Use of schemaLocation attribute
This should take the value (namespace) (URI) where the namespace is the targetNamespace of the schema and the URI is the location of the schema. In your case you appear to be using the schema file name as your target namespace. Additionally, looking at your code, you are loading the schema into your xml reader so you don't actually need the schemaLocation attribute at all. This is an optional attribute and some parsers completely ignore it.
I would suggest the following changes:
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://MyMoreMeaningfulNamespace"
xmlns="http://MyMoreMeaningfulNamespace"
elementFormDefault="qualified"
>
<xs:element name="Root">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Incident" type="IncidentType"/>
<xs:element maxOccurs="unbounded" name="PersonOfInterest" type="PersonOfInterestType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="IncidentType">
<xs:sequence>
<xs:element name="Description" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="PersonOfInterest" type="PersonOfInterestType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="PersonOfInterestType">
<xs:sequence>
<xs:element name="Name" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Which validates this instance
<Root xmlns="http://MyMoreMeaningfulNamespace">
<Incident>
<Description>something happened</Description>
<PersonOfInterest>
<Name>Joe</Name>
</PersonOfInterest>
<PersonOfInterest>
<Name>Sue</Name>
</PersonOfInterest>
</Incident>
<Incident>
...
</Incident>
<PersonOfInterest>
<Name>Manny</Name>
</PersonOfInterest>
<PersonOfInterest>
...
</PersonOfInterest>
</Root>

XML verification with XSD: attribute is not declared. But it is - see example

I'm having a problem validating XML against schema. Simplified code and examples:
Verification code:
public static void ValidateXmlAgainstSchema(StreamReader xml, XmlSchema xmlSchema)
{
var settings = new XmlReaderSettings { IgnoreWhitespace = true, IgnoreComments = true };
settings.Schemas.Add(xmlSchema);
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += (obj, args) => { if (args.Exception != null) throw args.Exception; };
using (var reader = XmlReader.Create(xml, settings))
using (XmlReader validatingReader = XmlReader.Create(reader, settings))
{
while (validatingReader.Read()){}
}
}
Schema:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://foo.com/"
xmlns="http://foo.com/">
<xs:simpleType name="myBool">
<xs:restriction base="xs:string">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
<xs:enumeration value="file_not_found"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="dataType">
<xs:sequence>
<xs:element name="id" type="xs:string" minOccurs="1" maxOccurs="1" />
<xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="1" />
</xs:sequence>
</xs:complexType>
<xs:element name="foo">
<xs:complexType>
<xs:sequence>
<xs:element name="data" type="dataType" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="myBool" type="myBool" use="optional" />
</xs:complexType>
</xs:element>
</xs:schema>
XML:
1.
<?xml version="1.0"?>
<foo xmlns="http://foo.com/" myBool="true">
<data>
<id>1</id>
<name>abc</name>
</data>
</foo>
This example throws an exception:
System.Xml.Schema.XmlSchemaValidationException: The element 'foo' in namespace 'http://foo.com/' has invalid child element 'data'
in namespace 'http://foo.com/'. List of possible elements expected: 'data'.
My understanding is that if the namespace is defined for an element, all child elements will have the same namespace, unless defined otherwise. It doesn't work though. I can make it validate by adding elementFormDefault="qualified" to the schema, which makes all elements default to targetNamespace. Is that a good way of doing it?
2.
<?xml version="1.0"?>
<a:foo xmlns:a="http://foo.com/" a:myBool="true">
<a:data>
<a:id>1</a:id>
<a:name>abc</a:name>
</a:data>
</a:foo>
This example fails with the message:
The 'http://foo.com/:myBool' attribute is not declared.
Every element and attribute has an explicit namespace, so the xml should be valid. Even the error message suggest parser is looking for the attribute I expect it to, but fails to find it. I can make it validate by changing a:myBool to myBool. Why doesn't it work in the first form and works in the other?
elementFormDefault won't do anything to attributes, to set the equivilent for those you need attributeFormDefault. However, by default both of these are set to "unqualified".
The reason approach 2 - a:myBool="true" - failed is becuase the attributeFormDefault value wasn't overridden. If you want to namespace attributes, you can either set this to "qualified" or set the form attribute on the attribute declaration itself to "qualified", like so:
<xs:attribute name="myBool" type="myBool" use="optional" form="qualfied"/>
This should make this a valid element start for approach 2:
<a:foo xmlns:a="http://foo.com/" a:myBool="true">
As for why approach 1 failed, I'm not sure, your XSD and XML match. It might be worth adding setting the attributeFormDefault attribute on the root XSD element to "unqualified", just in case the XSLT engine doesn't recognise their default settings when they aren't declared. Like so:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://foo.com/"
attributeFormDefault="unqualified"
xmlns="http://foo.com/">

Categories

Resources