【问题标题】:XDocument and Linq returns null if the element has xmlns attribute如果元素具有 xmlns 属性,则 XDocument 和 Linq 返回 null
【发布时间】:2011-05-09 16:04:11
【问题描述】:

XDocuments 和 Linq 的新手,请提出一个从 xml 字符串中的特定标签检索数据的解决方案:

如果我有来自 web 服务响应的 XML 字符串(为方便起见,我格式化了 xml):

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <GetCashFlowReportResponse xmlns="http://tempuri.org/">
      <GetCashFlowReportPdf>Hello!</GetCashFlowReportPdf>
    </GetCashFlowReportResponse>
  </soap:Body>
</soap:Envelope>

使用下面的代码,我只能在GetCashFlowReportResponse 标签没有"xmlns" 属性的情况下获取值。不知道为什么?否则,它总是返回 null。

string inputString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><GetCashFlowReportResponse xmlns=\"http://tempuri.org/\"><GetCashFlowReportPdf>Hello!</GetCashFlowReportPdf></GetCashFlowReportResponse></soap:Body></soap:Envelope>"    
XDocument xDoc = XDocument.Parse(inputString);
//XNamespace ns = "http://tempuri.org/";
XNamespace ns = XNamespace.Get("http://tempuri.org/");

var data = from c in xDoc.Descendants(ns + "GetCashFlowReportResponse")
           select (string)c.Element("GetCashFlowReportPdf");

foreach (string val in data)
{
    Console.WriteLine(val);
}

我无法更改 Web 服务以删除该属性。有没有更好的方法来读取响应并将实际数据返回给用户(以更易读的形式)?

编辑: 解决方案:

XDocument xDoc = XDocument.Parse(inputString);
XNamespace ns = "http://tempuri.org/";

var data = from c in xDoc.Descendants(ns + "GetCashFlowReportResponse")
           select (string)c.Element(ns + "GetCashFlowReportPdf");
foreach (string val in data)
{
   Console.WriteLine(val);
}

注意:即使所有子元素都没有命名空间属性,如果您将“ns”添加到元素中,代码也会起作用,因为我猜孩子会从父元素继承命名空间(请参阅 SLaks 的回复)。

【问题讨论】:

  • 感谢所有回复,但不知道为什么没有返回任何结果。我尝试了所有三种解决方案,结果仍然是相同的“null”。不确定我是否遗漏了什么。更新的代码在我的原始帖子中。我也尝试了“spender”的解决方案,但也返回了 null。有什么想法吗?

标签: c# xml linq-to-xml


【解决方案1】:

你需要包含命名空间:

XNamespace ns = "http://tempuri.org/";

xDoc.Descendants(ns + "GetCashFlowReportResponse")

【讨论】:

  • @user: GetCashFlowReportPdf 继承命名空间。您还需要在此处添加ns
  • 不,只有GetCashFlowReportResponse 有命名空间。其他元素没有。
  • @user:错了。默认命名空间 (xmlns="...") 由子元素继承。
  • 如果我将命名空间添加到GetCashFlowReportPdf,那么它可以工作,但我无权访问 web 服务代码来更改任何内容。我只是动态调用服务并读取 HttpWebResponse。我还有哪些其他选择?
  • @user:写c.Element(ns + "GetCashFlowReportPdf")
【解决方案2】:
XName qualifiedName = XName.Get("GetCashFlowReportResponse", 
    "http://tempuri.org/");

var data = from d in xDoc.Descendants(qualifiedName)

【讨论】:

    【解决方案3】:

    只要求使用限定名称的元素:

    // create a XML namespace object
    XNamespace ns = XNamespace.Get("http://tempuri.org/");
    
    var data = from c in xDoc.Descendants(ns + "GetCashFlowReportResponse")
               select (string)c.Element(ns + "GetCashFlowReportPdf");
    

    注意重载 + 运算符的使用,它使用 XML 命名空间和本地名称字符串创建 QName。

    【讨论】:

    • 拥有像 XNamespace ns = "tempuri.org"; 这样的代码有什么不同?并添加 XNamespace.Get()?
    • 我的回答使用了隐式转换;它们是等价的。
    猜你喜欢
    • 1970-01-01
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-01
    • 1970-01-01
    相关资源
    最近更新 更多