2

I'm using XML serialization with XmlSerializer. Before I read a document I try to validate it against XSD to determine the correct version to select.

The validation succeeds - but should fail!

My validation code is:

var schemaSet = new XmlSchemaSet();
schemaSet.Add(null, XmlReader.Create(new StringReader(xsd)));

var document = XDocument.Load(new StringReader(xml));

var hasErrors = false;
document.Validate(schemaSet, (s, e) => hasErrors = true);

Console.WriteLine("Document has erros: {0}", hasErrors);
if (hasErrors == false)
    Console.WriteLine("!!!! THIS DOCUMENT IS VALID !!!!");

Output is:

Document has erros: False
!!!! THIS DOCUMENT IS VALID !!!!

DEMO

Also the code suggested by MSDN will validate successfully (also included in DEMO - commented out):

var settings = new XmlReaderSettings();
settings.Schemas.Add(null, XmlReader.Create(new StringReader(xsd)));
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings;
settings.Schemas.Compile();

var contentReader = XmlReader.Create(new StringReader(xml), settings);
var document = new XmlDocument();
document.Load(contentReader);

var hasErrors = false;
document.Validate((s, e) => hasErrors = true);
Console.WriteLine("Document has erros: {0}", hasErrors);
if (hasErrors == false)
    Console.WriteLine("!!!! THIS DOCUMENT IS VALID !!!!");

The XSD for testing was stripped down to only one type containing only one property:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
    targetNamespace="http://www.xxx.de/V1_1/LightningChartConfiguration"
    elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.xxx.de/V1_1/LightningChartConfiguration" xmlns:tns="http://www.xxx.de/V1/Common" xmlns:pref="http://www.xxx.de/V1/Triggers">

    <xsd:element name="root" type="LightningChartConfigurationRoot_1_1"></xsd:element>

    <xsd:complexType name="LightningChartConfigurationRoot_1_1">
        <xsd:sequence>
            <xsd:element name="Version" maxOccurs="1" minOccurs="1">
                <xsd:simpleType>
                    <xsd:restriction base="xsd:string">
                        <xsd:enumeration value="V1_1"></xsd:enumeration>
                    </xsd:restriction>
                </xsd:simpleType>
            </xsd:element>
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

The XML to test is:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xxx.de/LightningChartConfiguration">
  <Version>V1_0</Version>
  <LastChanged>2020-09-11T05:38:07.333359Z</LastChanged>
  <Data>
    <Discriminator>{DCA61812-A355-4709-A252-AC20EF7AE3E1}</Discriminator>
    <Nodes>
      <Node xsi:type="NodeChart_1_0">
        <NodeId>365325c7-6cbd-4e29-af16-b044ee2a141f</NodeId>
        <ImageIndex>3</ImageIndex>
        <DisplayName>Chart</DisplayName>
        <ValueType>DateTime</ValueType>
        <TimeDisplayType>Absolute</TimeDisplayType>
        <XAxisLabelsTimeFormat>HH:mm:ss:fff</XAxisLabelsTimeFormat>
        <XAxisRange>10</XAxisRange>
        <Trigger>
          <IsActive xmlns="http://www.xxx.de/V1/Triggers">false</IsActive>
          <StartingMode xmlns="http://www.xxx.de/V1/Triggers">Undefined</StartingMode>
          <StoppingMode xmlns="http://www.xxx.de/V1/Triggers">Undefined</StoppingMode>
          <Items xmlns="http://www.xxx.de/V1/Triggers" />
        </Trigger>
        <XAxisTitleVisible>true</XAxisTitleVisible>
        <RefreshRate>15</RefreshRate>
        <LegendBoxVisible>true</LegendBoxVisible>
        <LegendBoxPosition>9</LegendBoxPosition>
      </Node>
      <Node xsi:type="NodeYAxis_1_0">
        <NodeId>8af383f1-bf1a-4b1f-8cb4-bb2ee33a53be</NodeId>
        <ImageIndex>4</ImageIndex>
        <Parent>365325c7-6cbd-4e29-af16-b044ee2a141f</Parent>
        <DisplayName>Y-Achse</DisplayName>
        <AutoRange>true</AutoRange>
        <From>0</From>
        <To>10</To>
        <Color>#FF008000</Color>
        <ShowGridLines>false</ShowGridLines>
        <YAxisTitleVisible>true</YAxisTitleVisible>
      </Node>
      <Node xsi:type="NodeSeries_1_0">
        <NodeId>9f92503e-1cd7-4120-9602-0da6394db17a</NodeId>
        <ImageIndex>1</ImageIndex>
        <Parent>8af383f1-bf1a-4b1f-8cb4-bb2ee33a53be</Parent>
        <DisplayName>Testing XXXXXX</DisplayName>
        <Color>#FF00FF7F</Color>
        <Width>1</Width>
        <Pattern>Solid</Pattern>
        <Scale>1</Scale>
        <ShowInLegendBox>true</ShowInLegendBox>
        <PhysicalDimension>NoDimension</PhysicalDimension>
        <PhysicalUnit>NoUnit</PhysicalUnit>
        <Data>Testing</Data>
      </Node>
    </Nodes>
  </Data>
</root>

The XML is obviously much too large and contains a lot more tags as allowed by XSD. Nevertheless the XSD-Validation succeeds without any errors. The only tag allowed in XSD is version that has a restriction to V1_1 wheras in XML it is V1_0.

I created a DEMO that reproduces this wired behaviour.

What am I missing here? What do I need to do to make the XSD validation work as expected?

If you copy the XSD and XML to e.g. this page the validation will fail as expected.

Sebastian Schumann
  • 3,204
  • 19
  • 37
  • https://stackoverflow.com/questions/17232575/xdocument-validate-is-always-successful – CodeCaster Sep 11 '20 at 08:50
  • Per the linked dupe's answer, "your schema doesn't have any opinion on elements in namespaces other than its `targetNamespace`". If you change your xml's namespace to *exactly* the `targetNamespace` of the xsd, then `Validate` results in errors. https://dotnetfiddle.net/lt778s is your fiddle with just this change. – AakashM Sep 11 '20 at 08:53
  • @CodeCaster What are you trying to tell me? My XSD does contain a namespace so the answer will not work for my case - or is there something that I'm missing? – Sebastian Schumann Sep 11 '20 at 08:56
  • @AakashM What? I can't change the namespace to match exactly because there are different versions of types included and they derive from a typ in another XSD. Both types have to be in seperate namespaces to generate C#-Classes. Sorry this is not possible for me. BTW: If I have an XSD to validate input in my app and the user provides any (maybe hacked) XML the validation will succeed. What design decisions lead to that behaviour? Yes you might be right that this will work but it's impractical if your app works on multiple XMLs and the user selects the wrong one. – Sebastian Schumann Sep 11 '20 at 09:01
  • In which case you might prefer this approach https://stackoverflow.com/a/17233188/71059 – AakashM Sep 11 '20 at 09:03
  • 1
    @AakashM Okay. I [tested it](https://dotnetfiddle.net/S9BD0s) and it seems to work - but the linked question reports weak validation due to non existing namespaces. I misinterpreted the answer. I appologize. – Sebastian Schumann Sep 11 '20 at 09:12
  • I agree - this should fail but the error should be something like no information found for element "root" - ie it should essentially just not recognise it but it should also flag that fact. If alternatively you pass in the targetNamespace of the schema instead of the null in the line schemaSet.Add(null, XmlReader.Create(new StringReader(xsd))); then everything works as expected. So; schemaSet.Add("http://www.xxx.de/V1_1/LightningChartConfiguration", XmlReader.Create(new StringReader( xsd ))); – walbury Feb 15 '21 at 13:52
  • @walbury Thx for that information. I'll test it in the future. The main problem is that the deserialization code is wrapped into a persistence framework that works using business logic objects instead of persisted objects. Currently there is only the XSD injected. At the moment there is no extra value that holds the namespace and I don't want to parse the XSD. But I'll give it a try because it sounds like a cleaner solution. – Sebastian Schumann Feb 16 '21 at 05:24

0 Answers0