Search code examples
c#xmlwindows-10-mobile

XDocument get element that defines it's own namespace


As question states. I have a xml document (below) and I need to get X_ScalarWebApi_DeviceInfo that defines namespace urn:schemas-sony-com:av. Unfortunately it results in an error: {System.NullReferenceException: Object reference not set to an instance of an object. I'm mainly interested in ServiceList element, but it doesn't work as well. Platform - Windows 10 mobile. Any ideas?

<?xml version="1.0"?>
    <root xmlns="urn:schemas-upnp-org:device-1-0">    
        <specVersion>
            <major>1</major>
            <minor>0</minor>
        </specVersion>    
        <device>
            <deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>
            <friendlyName>ILCE-6000</friendlyName>
            <manufacturer>Sony Corporation</manufacturer>
            <manufacturerURL>http://www.sony.net/</manufacturerURL>
            <modelDescription>SonyDigitalMediaServer</modelDescription>
            <modelName>SonyImagingDevice</modelName>
            <UDN>uuid:000000001000-1010-8000-62F1894EE7BE</UDN>    
            <serviceList>
               <service>
                   <serviceType>urn:schemas-sony-com:service:ScalarWebAPI:1</serviceType>
                   <serviceId>urn:schemas-sony-com:serviceId:ScalarWebAPI</serviceId>
                   <SCPDURL/>
                   <controlURL/>
                   <eventSubURL/>
               </service>
            </serviceList>
            <av:X_ScalarWebAPI_DeviceInfo xmlns:av="urn:schemas-sony-com:av">
                <av:X_ScalarWebAPI_Version>1.0</av:X_ScalarWebAPI_Version>
                <av:X_ScalarWebAPI_ServiceList>
                    <av:X_ScalarWebAPI_Service>
                        <av:X_ScalarWebAPI_ServiceType>guide</av:X_ScalarWebAPI_ServiceType>
                        <av:X_ScalarWebAPI_ActionList_URL>http://192.168.122.1:8080/sony</av:X_ScalarWebAPI_ActionList_URL>
                        <av:X_ScalarWebAPI_AccessType/>
                    </av:X_ScalarWebAPI_Service>
                    <av:X_ScalarWebAPI_Service>
                        <av:X_ScalarWebAPI_ServiceType>accessControl</av:X_ScalarWebAPI_ServiceType>
                        <av:X_ScalarWebAPI_ActionList_URL>http://192.168.122.1:8080/sony</av:X_ScalarWebAPI_ActionList_URL>
                        <av:X_ScalarWebAPI_AccessType/>
                    </av:X_ScalarWebAPI_Service>
                    <av:X_ScalarWebAPI_Service>
                        <av:X_ScalarWebAPI_ServiceType>camera</av:X_ScalarWebAPI_ServiceType>
                        <av:X_ScalarWebAPI_ActionList_URL>http://192.168.122.1:8080/sony</av:X_ScalarWebAPI_ActionList_URL>
                        <av:X_ScalarWebAPI_AccessType/>
                    </av:X_ScalarWebAPI_Service>
                </av:X_ScalarWebAPI_ServiceList>
            </av:X_ScalarWebAPI_DeviceInfo>
        </device>
    </root>

Ah, the code:

XDocument xDoc = XDocument.Parse(xml_text);
//var av = xDoc.Root.GetDefaultNamespace();//.Attribute("xmlns");//
XNamespace av = "urn:schemas-sony-com:av";
System.Diagnostics.Debug.WriteLine(av);
<XElement> api_list = (List<XElement>)xDoc.Element(av + "X_ScalarWebAPI_DeviceInfo").Elements();

==EDIT== Well, both solutions were ok, so I'm upvoting one and marking as answer the other :P It was mentioned that the solution using only a 'local name' might cause false positive search results, so to be safe I'm using the first one. Thanks for help!


Solution

  • Element only returns elements directly beneath the current node. You need the to specify the entire path (note there are multiple namespaces):

    XNamespace ns = "urn:schemas-upnp-org:device-1-0";
    XNamespace av = "urn:schemas-sony-com:av";
    
    var api_list = xDoc.Root.Element(ns + "device")
        .Element(av + "X_ScalarWebAPI_DeviceInfo").Elements();