【问题标题】:Unable to extract child element from an XML using XDocument无法使用 XDocument 从 XML 中提取子元素
【发布时间】:2019-11-05 14:43:54
【问题描述】:

以下是我试图从中提取子元素的 XML。

<?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;
}

我想提取元素安全令牌。

以下是我已经做过的事情:

  • 尝试使用帖子中建议的方法提取元素 How to get value of child node from XDocument

  • 还发布了一些代码供参考。这两种说法都是 将值分配给 Token 变量正在抛出“未设置对象 到一个对象的实例”异常。

提前致谢。

【问题讨论】:

  • 这看起来像是 Amadeus 响应。为什么您尝试自己解析 SOAP 响应而不是使用例如 WCF?
  • 你用艾玛迪斯得到了我!好吧,我正在尝试提取安全令牌并将其放入 SOAP 标头中,以发送对企业 API 操作之一的请求……它是从我的旧代码升级到 SOAP 4.0 的一部分。

标签: c# xml amadeus


【解决方案1】:

您需要考虑Header 的命名空间。

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;
}

其实你可以直接调用

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

【讨论】:

  • @GurunathRao 我做了一个你可能感兴趣的小编辑
  • 是的,使用 LINQ 会更好!
【解决方案2】:

仅对于 this 响应,只解析字符串并提取元素是有意义的。 此响应使用两个命名空间,一个用于 SOAP 标头,另一个用于 Amadeus 登录响应。您需要第二个来检索令牌:

//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;

其他 Amadeus 响应是巨大的,XDocument 不会比使用 WCF 和反序列化强类型对象好多少(如果有的话)。 XDocument 反序列化整个 XML 响应,与 DataContractSerializer 相同。但是,您获得的不是一组强类型的对象,而是您必须映射到其他东西的 XElement。

如果您想通过仅读取部分来减少内存消耗,则必须使用 XmlReader 并从响应流中一一读取 XML 令牌。这还有很多工作要做。

另一个有趣的事情是 Amadeus 响应使用 多个 命名空间。此响应仅使用 2 个。其他响应(例如搜索)使用更多。

【讨论】:

  • 感谢您的建议!我已经在使用强类型类方法来反序列化响应。此外,此请求具有较少的命名空间,因为它被用于获取少量安全凭证,而这些凭证又将用于下线的另一个进程。
【解决方案3】:

您可以考虑使用System.Xml.XmlDocumentSystem.Xml.XPath.XPathNavigator,它们真的很容易使用。

我给你写了一个简单的例子(支持UTF-8编码):

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
}

请注意,您还可以:

  • 使用“@”键提取内部值。

  • 使用xmlNavigator.MoveToNext()移动到孩子。

还有许多其他你可以阅读的内容here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-30
    • 1970-01-01
    • 2019-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多