Unable to extract child element from an XML using XDocument

跟風遠走 提交于 2020-01-25 08:49:05

问题


Following is the XML from which I am trying to extract a child element.

<?xml version="1.0" encoding="UTF8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header xmlns="http://SomeValue/SomeValue/2009/01/SomeValue.xsd">
<Session>
<SessionId>SomeValue</SessionId>
<SequenceNumber>1</SequenceNumber>
<SecurityToken>SomeValue</SecurityToken>
</Session>
</soap:Header>
<soap:Body>
<Security_AuthenticateReply xmlns="http://SomeValue/SomeValue">
<processStatus>
<statusCode>P</statusCode>
</processStatus>
</Security_AuthenticateReply>
</soap:Body>
</soap:Envelope>
public static string AssignSecurityToken(string response)
{
        string Token = "";

        XNamespace ns = "http://schemas.xmlsoap.org/soap/envelope/";
        XElement xdoc = XElement.Parse(response);
        XElement root = xdoc.Descendants(ns + "Header").First();

        Token = root.Element("Session").Element("SecurityToken").Value;

        Token = root.Descendants("Session").Descendants().Where(n => n.Name == "SecurityToken").FirstOrDefault().Value;
        return Token;
}

I want to extract the element Security Token.

Following are the things that I have already worked on:

  • Tried extracting the element using the approach suggested in the post How to get value of child node from XDocument

  • Also posting some code for reference. Both the statements that are assigning values to the Token variable are throwing "Object not set to an instance of an object"exception.

Thanks in advance.


回答1:


You need to take into account the Header's namepace.

public static string AssignSecurityToken(string response)
{
    XNamespace ns1 = "http://schemas.xmlsoap.org/soap/envelope/";
    XNamespace ns2 = "http://SomeValue/SomeValue/2009/01/SomeValue.xsd";

    var envelope = XElement.Parse(response);
    var header = envelope.Element(ns1 + "Header");
    var session = header.Element(ns2 + "Session");
    var security_token = session.Element(ns2 + "SecurityToken");

    return security_token.Value;
}

Actually you could go ahead and just call

return XElement.Parse(response).Descendants()
            .First(x => x.Name.LocalName == "SecurityToken").Value;



回答2:


For this response only, it makes sense to just parse the string and extract an element. This response uses two namespaces, one for SOAP headers and another for the Amadeus login response. You need the second one to retrieve the token :

//SOAP-only namespace
XNamespace soap = "http://schemas.xmlsoap.org/soap/envelope/";
//Default namespace
XNamespace ns = "http://SomeValue/SomeValue/2009/01/SomeValue.xsd";

var response=XElement.Parse(xml);
var token=response.Descendants(ns+"SecurityToken").First().Value;

Other Amadeus responses are huge and XDocument won't be much better (if at all) than using WCF and deserializing to strongly typed objects. XDocument deserializes the entire XML response, the same as DataContractSerializer. Instead of getting back a strongly-typed set of objects though, you get XElements you'll have to map to something else.

If you want to reduce memory consumption by only reading the parts you'll have to use XmlReader and read the XML tokens from the response stream one by one. That's a lot more work.

Another interesting thing is that Amadeus responses use multiple namespaces. This response uses just 2. Other responses, eg searches, use many more.




回答3:


You might consider working with System.Xml.XmlDocument and System.Xml.XPath.XPathNavigator which are really easy to work with.

I wrote a simple example for you (supporting UTF-8 encoding):

System.Xml.XmlDocument someXmlFile = new System.Xml.XmlDocument();
string xmlPath= @"YOUR_XML_FULL_PATH";
string innerNodeToExtract= @"/Session/SecurityToken";

try
{
    // Loading xml file with utf-8 encoding:
    string xmlFileStr= Systm.IO.File.ReadAllText(xmlPath, System.Text.Encoding.UTF8);

    // Creating the XPathNavigator:
    System.Xml.XPath.XPathNavigator xmlNavigator= someXmlFile.CreateNavigator();

    // Getting the inner value as string:
    string value = xmlNavigator.SelectSingleNode(innerNodeToExtract).Value;

    // some code...
}
catch(Exception) 
{
    // Handle failures
}

Please notice that you can also:

  • Extract inner values using "@" key.

  • Move to the child using xmlNavigator.MoveToNext().

And many other things that you can read here.



来源:https://stackoverflow.com/questions/58713757/unable-to-extract-child-element-from-an-xml-using-xdocument

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!