读取异常 xml 的节点 - XmlDocument - 表达式必须评估为节点集

Posted

技术标签:

【中文标题】读取异常 xml 的节点 - XmlDocument - 表达式必须评估为节点集【英文标题】:Read node of unusual xml - XmlDocument - Expression must evaluate to a node-set 【发布时间】:2020-05-29 01:51:49 【问题描述】:

我已经阅读并尝试了许多线程 - this answer、this 和 this answer。但是,它们不适用于我,因为我真的没有通常的 xml:

var xmlString = @"<?xml version=""1.0"" encoding=""windows-1251""?>
<GetReply>
    <InformOne>87</InformOne>
        <InfoReply>
            <![CDATA[<?xml version='1.0' encoding='UTF-8'?>
            <S:Container xmlns:S=""http://schemas.xmlsoap.org/soap/envelope/"">
                <S:Body>
                    <ns2:getReference31IPOResponse xmlns:ns2 = ""http://service.one.com/"" >
                        <return>
                            <reference31_1IPO xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:nil=""true""/>
                            <reference31_2IPO xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:nil=""true""/>
                            <amount>0</amount>
                            <codeTypeObject>0</codeTypeObject>
                            <returnCode>4</returnCode>
                            <errorCode>0</errorCode>
                            <errorMessage>Something was wrong</errorMessage>
                            <title>Foo Data</title>
                        </return>
                    </ns2:getReference31IPOResponse>
                </S:Body>
            </S:Container>]]>
        </InfoReply>
</GetReply>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
var errorMessage = xmlDoc.SelectSingleNode("/GetReply/InformOne/InfoReply/CDATA/S:Container/S:Body/ns2:getReference31IPOResponse/return/errorMessage");

但是,我看到以下错误:

'表达式必须计算为节点集。'

另外,我什至尝试获取InfoReply,但是错误是一样的:

var errorMessage = xmlDoc.SelectSingleNode("/GetReply/InformOne/InfoReply/");

我想要阅读errorMessage 节点中的文本?

你能告诉我,我做错了什么吗? 任何帮助将不胜感激。

看起来&lt;![CDATA[&lt;?xml version='1.0' encoding='UTF-8'?&gt; 中断读取其余节点。

【问题讨论】:

那么,您想要来自&lt;errorMessage&gt;Something was wrong&lt;/errorMessage&gt; 的值吗? @PavelAnikhouski 你是绝对正确的 为什么不用Xml.Linq呢? @PavelAnikhouski 好的,让我们尝试使用Xml.linq 【参考方案1】:

1 - 你忘记了命名空间,你需要添加它们 XmlNamespaceManager

2 - 您还需要将您的Xml 分成两个sub Xml,一个在CDATA 之前,另一个在它之后。

将您的代码更改为:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);

XmlNamespaceManager mgr = new XmlNamespaceManager(xmlDoc.NameTable);
mgr.AddNamespace("S", "http://schemas.xmlsoap.org/soap/envelope/");
mgr.AddNamespace("ns2", "http://service.one.com/");
mgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");

var infoReply = xmlDoc.SelectSingleNode("//GetReply/InfoReply", mgr);

XmlDocument requestDocument = new XmlDocument();
requestDocument.LoadXml(infoReply.InnerText);

var errorMessageNode = requestDocument.SelectSingleNode("/S:Container/S:Body/ns2:getReference31IPOResponse/return/errorMessage", mgr);
string errorMessage = errorMessageNode?.InnerText;

希望对你有所帮助。

【讨论】:

伙计,你太棒了!非常感谢!祝你今天过得愉快!伟大的!谢谢!:)【参考方案2】:

我不知道你为什么在 xml 中有 CData 块。我删除了 CData 并使用了以下 xml

<?xml version="1.0" encoding="windows-1251"?>
<GetReply>
    <InformOne>87</InformOne>
        <InfoReply>
            <S:Container xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
                <S:Body>
                    <ns2:getReference31IPOResponse xmlns:ns2 = "http://service.one.com/" >
                        <return>
                            <reference31_1IPO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
                            <reference31_2IPO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
                            <amount>0</amount>
                            <codeTypeObject>0</codeTypeObject>
                            <returnCode>4</returnCode>
                            <errorCode>0</errorCode>
                            <errorMessage>Something was wrong</errorMessage>
                            <title>Foo Data</title>
                        </return>
                    </ns2:getReference31IPOResponse>
                </S:Body>
            </S:Container>
        </InfoReply>
</GetReply>

然后使用以下xml linq:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;


namespace ConsoleApplication1

    class Program
    
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        
            string xml = File.ReadAllText(FILENAME);
            XDocument doc = XDocument.Parse(xml);

            Dictionary<string, string> dict = doc.Descendants().Where(x => x.Name.LocalName == "return")
                .FirstOrDefault().Elements().Where(x => (string)x != string.Empty)
                .GroupBy(x => x.Name.LocalName, y => (string)y)
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());


        
    


【讨论】:

感谢您的回复!我有一些问题: 1. xml 可以有cdata 标签吗?是否符合条件? 2. 能不能指点一下删除CData的方法?我无法手动删除 是的 CDate 是允许的,但不包含 xml 标签,并且没有第二个缩进行

以上是关于读取异常 xml 的节点 - XmlDocument - 表达式必须评估为节点集的主要内容,如果未能解决你的问题,请参考以下文章

java如何读取xml节点元素值?

C#如何读取XML中指定的节点值?

读取 XML 元素时出现异常

C#如何读取xml文件里面节点里面的属性信息?

c# xPathDocument读取xml节点属性

C#读取xml