Search code examples
xmlxpathxsd.net-6.0

XPath with single /nodeName does not return the child node


XML -

<?xml version="1.0" encoding="utf-8" ?>

<tns:q1 xmlns:tns="http://tempuri.org/XMLSchema2.xsd"
        id="s1.q1" description="" text="How would you rate the system of nuclear laws and regulations in force in the State with respect to safeguards implementation?" isAnsewerRequired="true" condition="/tns:choices">
    <tns:choices>
        <tns:c1 id="s1.q1.c1" text="Complete and exhaustive" description="No action is needed." isCommentRequired="false" >false</tns:c1>
        <tns:c2 id="s1.q1.c2" text="Overall satisfactory" description="There is a sufficient system of laws and regulations; however, there are few aspects which are not covered (for instance on exempted material, small quantities, extent of authority, etc.)." isCommentRequired="false">false</tns:c2>
        <tns:c3 id="s1.q1.c3" text="Insufficient" description="The system of laws and regulations is not sufficient to support effective SG implementation." isCommentRequired="true">false</tns:c3>
        <tns:c4 id="s1.q1.c4" text="Not existent or largely incomplete" description="The system of laws and regulations is practically inexistent." isCommentRequired="true">true</tns:c4>
    </tns:choices>
    <tns:comment title="Comment"></tns:comment>
</tns:q1>

Schema -

<?xml version="1.0" encoding="utf-8"?>

<xs:schema targetNamespace="http://tempuri.org/XMLSchema2.xsd" 
                     xmlns:tns="http://tempuri.org/XMLSchema2.xsd"
    elementFormDefault="qualified" attributeFormDefault="unqualified"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
        
>
    <xs:element name="q1">
        <xs:complexType>
            <xs:sequence>
                
                <xs:element name="choices" maxOccurs="1" minOccurs="1">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="c1" maxOccurs="1" minOccurs="1">
                                <xs:complexType>
                                    <xs:simpleContent>
                                        <xs:extension base="xs:boolean">
                                            <xs:attribute name="id" type="xs:string" fixed="s1.q1.c1"/>
                                            <xs:attribute name="text" type="xs:string" fixed="Complete and exhaustive"/>
                                            <xs:attribute name="description" type="xs:string" fixed="No action is needed."/>
                                            <xs:attribute name="isCommentRequired" type="xs:boolean" fixed="false"/>
                                        </xs:extension>
                                    </xs:simpleContent>
                                </xs:complexType>
                            </xs:element>

                            <xs:element name="c2" maxOccurs="1" minOccurs="1">
                                <xs:complexType>
                                    <xs:simpleContent>
                                        <xs:extension base="xs:boolean">
                                            <xs:attribute name="id" type="xs:string" fixed="s1.q1.c2"/>
                                            <xs:attribute name="text" type="xs:string" fixed="Overall satisfactory"/>
                                            <xs:attribute name="description" type="xs:string" fixed="There is a sufficient system of laws and regulations; however, there are few aspects which are not covered (for instance on exempted material, small quantities, extent of authority, etc.)."/>
                                            <xs:attribute name="isCommentRequired" type="xs:boolean" fixed="false"/>
                                        </xs:extension>
                                    </xs:simpleContent>
                                </xs:complexType>
                            </xs:element>

                            <xs:element name="c3" maxOccurs="1" minOccurs="1">
                                <xs:complexType>
                                    <xs:simpleContent>
                                        <xs:extension base="xs:boolean">
                                            <xs:attribute name="id" type="xs:string" fixed="s1.q1.c3"/>
                                            <xs:attribute name="text" type="xs:string" fixed="Insufficient"/>
                                            <xs:attribute name="description" type="xs:string" fixed="The system of laws and regulations is not sufficient to support effective SG implementation."/>
                                            <xs:attribute name="isCommentRequired" type="xs:boolean" fixed="true"/>
                                        </xs:extension>
                                    </xs:simpleContent>
                                </xs:complexType>
                            </xs:element>

                            <xs:element name="c4" maxOccurs="1" minOccurs="1">
                                <xs:complexType>
                                    <xs:simpleContent>
                                        <xs:extension base="xs:boolean">
                                            <xs:attribute name="id" type="xs:string" fixed="s1.q1.c4"/>
                                            <xs:attribute name="text" type="xs:string" fixed="Not existent or largely incomplete"/>
                                            <xs:attribute name="description" type="xs:string" fixed="The system of laws and regulations is practically inexistent."/>
                                            <xs:attribute name="isCommentRequired" type="xs:boolean" fixed="true"/>
                                        </xs:extension>
                                    </xs:simpleContent>
                                </xs:complexType>
                            </xs:element>

                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                
                <xs:element name="comment" minOccurs="1" maxOccurs="1">
                    <xs:complexType>
                        <xs:simpleContent>
                            <xs:extension base="xs:string">
                                <xs:attribute name="title" type="xs:string" fixed="Comment"/>
                            </xs:extension>
                        </xs:simpleContent>
                    </xs:complexType>
                </xs:element>

            </xs:sequence>

            <xs:attribute name="id" type="xs:string" fixed="s1.q1"/>
            <xs:attribute name="text" type="xs:string" fixed="How would you rate the system of nuclear laws and regulations in force in the State with respect to safeguards implementation?"/>
            <xs:attribute name="description" type="xs:string" fixed=""/>
            <xs:attribute name="isAnsewerRequired" type="xs:boolean" fixed="true"/>
            <xs:attribute name="condition" type="xs:string" fixed="/tns:choices"/>
        </xs:complexType>
    </xs:element>

</xs:schema>

The C# code (net6) -

using System;
using System.Xml;
using System.Xml.Schema;

namespace Validation
{
    internal class Program
    {
        static void Main()
        {
            try
            {

                string xmlFilePath = "s1.xml";
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.Schemas.Add("http://tempuri.org/XMLSchema2.xsd", "s1.xsd"); 
                settings.ValidationType = ValidationType.Schema;
                ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler);

                // Create an XmlReader for the XML file
                using (XmlReader reader = XmlReader.Create(xmlFilePath, settings))
                {
                    XmlDocument document = new XmlDocument();
                    document.Load(reader);

                    var nsmgr = new XmlNamespaceManager(document.NameTable);
                    nsmgr.AddNamespace("tns", "http://tempuri.org/XMLSchema2.xsd");

                    document.Validate(eventHandler);
                    var nav = document.CreateNavigator();
                    var list = nav.Select("//*[@condition]", nsmgr);
                    while (list.MoveNext())
                    {
                        var item = list.Current;
                        //debugger shows that item is tns:q1 element
                        var condition = item.GetAttribute("condition", "");
                        //the condition read from tns:q1 node is "/tns:choices"
                        var result = item.Evaluate(condition, nsmgr);
                        //result shows 0 elements and I am expecting 1.
                        //If the condition is "//tns:choices" results contains 1 element.
                        if (result == null)
                        {
                            Console.WriteLine($"Validation error:Validation error");
                        }
                    }

                }


                Console.WriteLine("XML validation successful.");
                Console.ReadLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex.Message);
            }
        }
        private static void ValidationEventHandler(object sender, ValidationEventArgs args)
        {
            if (args.Severity == XmlSeverityType.Warning)
                Console.WriteLine("Warning: " + args.Message);
            else
                Console.WriteLine("Error: " + args.Message);
        }
    }
}

As in c# code comments, item.Evaluate with "/tns:choices" does not return any element, but only with "//tns:choices" that it returns choices element. However with same xml, and "/tns:choices" XPather.com return correctly.

What am I doing wrong?

Since its not allowing me to post it because there is more code than text; here I am trying to implement xs:assert like functionality. Since MS backed xml implementation supports only xsd1.0, and I do not want to use any third party implementation list SAXON, I have come up with this implementation.


Solution

  • You could change your XPath to have a relative path (default axis is the child axis):

    condition="tns:choices"
    

    When you have the leading slash: /tns:choices, then the XPath will "jump up" to the root node at the top of the tree and then look for tns:choices - but the document element is tns:q1, not tns:choices.

    You could also use the XPath: /tns:q1/tns:choices, or /*/tns:choices.