c0nn
c0nn

Reputation: 327

Manual addition of namespace to XElements fails upon validation

I was attempting to validate a group of XML tags that I have with an xsd file that I created, with the added constraint that all XElement's must belong to a namespace.

<xs:schema id="TestSchema"
  targetNamespace="http://test.org/test.xsd"
  xmlns="http://test.org/test.xsd"
  xmlns:mstns="http://test.org/test.xsd"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  >

<xs:element name="testRoot">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="testObject">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="foo" />
            <xs:element name="bar" />
          </xs:sequence>
          <xs:attribute name="testType" type="xs:int" use="required" />
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:element>

/xs:schema>

... where the XML that I start with appears as follows:

<testRoot>
  <testObject testType="2">
    <foo />
    <bar />
  </testObject>
</testRoot>

Any problems that may stem from the syntax of the element declarations is because this is simplified; interestingly, the XML validates against this schema when I don't bother trying to add namespaces to the elements.

Once the XML is parsed into LINQ to XML, I add namespaces to each element with an extension method:

public static void SetDefaultXmlNamespace(this XElement element, XNamespace ns)
{
    foreach (var item in element.DescendantsAndSelf())
    {
        item.Name = ns.GetName(item.Name.LocalName);
    }
}

But my attempts to validate this schema are unsuccessful. Attempting to create and validate against the above XML yields a cryptic error:

The element 'testRoot' in namespace 'http://test.org/test.xsd' has invalid child element 'testObject' in namespace 'http://test.org/test.xsd'. List of possible elements expected: 'testObject'.

I would expect such a simple example to succeed, but I'm clearly missing something.

I attempt the validation by converting the XElement tree in question into an XDocument and then validating:

string xsdMarkup = "schema here";
XElement testRoot; // declared elsewhere
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add(AppStateXmlMapper.SchemaNamespace, XmlReader.Create(new StringReader(xsdMarkup)));

XDocument xmlDoc = new XDocument(testRoot);
xmlDoc.Root.SetDefaultXmlNamespace(AppStateXmlMapper.Ns);
List<string> errorList = new List<string>();

// attempt validation
xmlDoc.Validate(schemas, (sender, args) =>
{
    errorList.Add(args.Message);
});

It's probably worth noting that I've tried adding constraints to the schema such as the elementFormDefault= "qualified" and attributeFormDefault="qualified" tag, but that simply changes the validation errors to other elements/attributes. I tried adding a namespace to every single attribute on the fly as well, but the validation issues persist. I'm sure the problem is in my xsd file somewhere, but I have no idea what that issue is. Any thoughts on my problem would be greatly appreciated.

EDIT:

When adding elementFormDefault= "qualified" to my schema, the validation errors change, to: The 'testType' attribute is not declared., and the accompanying error: The required attribute 'http://test.org/test.xsd:testType' is missing.

Upvotes: 0

Views: 365

Answers (1)

csauvanet
csauvanet

Reputation: 554

I think this is indeed due to namespace qualification, I do not know LINQ but it seems that the error:

The element 'testRoot' in namespace 'http://test.org/test.xsd' has nvalid child element 'testObject' in namespace 'http://test.org/test.xsd'. List of possible elements expected: 'testObject'

means the validator expects 'testObject' to be in no namespace while it received it in the 'http://test.org/test.xsd' namespace.

ElementFormDefault is by default unqualified, so that means the root of your schema needs the namespace qualification but that the sub-elements do not need it.

Considering both elementFormDefault and attributeFormDefault not set or set to unqualified, a valid XML instance of the schema above would be:

<tns:testRoot xmlns:tns="http://test.org/test.xsd">
  <testObject testType="2">
    <foo />
    <bar />
  </testObject>
</tns:testRoot>

So you should not add namespace to each element but only to the root one.

Let me know if I am not correct.

Upvotes: 1

Related Questions