在 C 语言中解析 SOAP 响应#

Parsing SOAP response in C#

提问人:tanatan 提问时间:2/2/2023 最后编辑:Tu deschizi eu inchidtanatan 更新时间:2/2/2023 访问量:582

问:

我是新 C#。我发出一个SOAP请求,在SOAP响应中,我需要访问重复节点“ABC”。这是我的SOAP响应的样子:

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
    <env:Header>
        <work:WorkContext xmlns:work="http://example.com/soap/workarea/">sdhjasdajsdhj=</work:WorkContext>
    </env:Header>
    <env:Body>
        <ReadABCResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.xyz.com/abc/a6/AB/XYZ/V1">
            <ABC xmlns="http://xmlns.xyz.example/abc/a6/AB/XYZ/V1">
                <asd xmlns="http://xmlns.example.com/abc/a6/AB/XYZ/V1" xsi:nil="true"/>
                <xyz xmlns="http://xmlns.example.com/abc/a6/AB/XYZ/V1" xsi:nil="true"/>
            </ABC>
            <ABC xmlns="http://xmlns.example.com/abc/a6/AB/XYZ/V1">
                <asd xmlns="http://xmlns.example.com/abc/a6/AB/XYZ/V1" xsi:nil="true"/>
                <xyz xmlns="http://xmlns.example.com/abc/a6/AB/XYZ/V1" xsi:nil="true"/>
            </ABC>
        </ReadABCResponse>
    </env:Body>
</env:Envelope>

我的代码如下:

XmlDocument responseDoc = new XmlDocument();
responseDoc.LoadXml(responseString); //responseString is set to above SOAP response.

XmlNamespaceManager nsmgr = new XmlNamespaceManager(responseDoc.NameTable);
nsmgr.AddNamespace("env", "http://schemas.xmlsoap.org/soap/envelope/");
nsmgr.AddNamespace("work", "http://example.com/soap/workarea/");
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
nsmgr.AddNamespace("", "http://xmlns.example.com/abc/a6/AB/XYZ/V1");

XmlNodeList lst = responseDoc.SelectNodes("/env:Envelope/env:Body/ReadABCResponse/ABC", nsmgr);
Console.WriteLine("Count " + lst.Count);

// and then iterate over the repeating ABC nodes to do some work.

但是,Count 的值始终打印为 0。我在“SelectNodes”方法中尝试了xpath路径的不同组合,包括“//ABC” - 我认为这应该给我所有重复的“ABC”节点,但它没有。

我的代码有什么问题。请有人突出显示并帮助我!

我在这个网站上环顾四周,但无法弄清楚这段代码出了什么问题。

C# XML 解析

评论

0赞 Fildor 2/2/2023
你没有WSDL文件吗?=> stackoverflow.com/q/2772708/982149

答:

1赞 Tu deschizi eu inchid 2/2/2023 #1

使用XDocument从XML中读取数据的方法如下。

测试 .xml

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
    <env:Header>
        <work:WorkContext xmlns:work="http://example.com/soap/workarea/">sdhjasdajsdhj=</work:WorkContext>
    </env:Header>
    <env:Body>
        <ReadABCResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.xyz.com/abc/a6/AB/XYZ/V1">
            <ABC xmlns="http://xmlns.xyz.example/abc/a6/AB/XYZ/V1">
                <asd xmlns="http://xmlns.example.com/abc/a6/AB/XYZ/V1" xsi:nil="true">asd data 1</asd>
                <xyz xmlns="http://xmlns.example.com/abc/a6/AB/XYZ/V1" xsi:nil="true">xyz data 1</xyz>
            </ABC>
            <ABC xmlns="http://xmlns.example.com/abc/a6/AB/XYZ/V1">
                <asd xmlns="http://xmlns.example.com/abc/a6/AB/XYZ/V1" xsi:nil="true">asd data 2</asd>
                <xyz xmlns="http://xmlns.example.com/abc/a6/AB/XYZ/V1" xsi:nil="true">xyz data 2</xyz>
            </ABC>
        </ReadABCResponse>
    </env:Body>
</env:Envelope>

添加以下 using 语句

  • using System.Xml;
  • using System.Xml.Linq;
  • using System.Diagnostics;

创建类(名称:ABC.cs)

public class ABC
{
    public string Asd { get; set; }
    public string Xyz { get; set; }
}

选项 1

private void GetABC()
{
    //ToDo: replace with your XML data
    string xmlText = "your XML data...";

    //parse XML
    XDocument doc = XDocument.Parse(xmlText);

    //create new instance
    List<ABC> abcs = new List<ABC>();

    foreach (XElement elem in doc.Descendants().Where(x => x.Name.LocalName == "ABC"))
    {
        //create new instance
        ABC abc = new ABC();

        foreach (XElement elemChild in elem.Descendants())
        {
            //Debug.WriteLine($"{elemChild.Name}: '{elemChild.Value?.ToString()}'");

            if (elemChild.Name.LocalName == "asd")
                abc.Asd = elemChild.Value?.ToString();
            else if (elemChild.Name.LocalName == "xyz")
                abc.Xyz = elemChild.Value?.ToString();
        }

        //add to List
        abcs.Add(abc);
    }

    foreach (ABC abc in abcs)
    {
        Debug.WriteLine($"ABC: '{abc.Asd}' XYZ: '{abc.Xyz}'");
    }
}

选项 2

private void GetABC()
{
    //ToDo: replace with your XML data
    string xmlText = "your XML data...";

    //parse XML
    XDocument doc = XDocument.Parse(xmlText);

    //get namespace
    XNamespace nsABC = doc.Descendants().Where(x => x.Name.LocalName == "ABC").FirstOrDefault().GetDefaultNamespace();

    List<ABC> abcs = doc.Descendants().Where(x => x.Name.LocalName == "ABC").Select(x2 => new ABC()
    {
        Asd = (string)x2.Element(nsABC + "asd"),
        Xyz = (string)x2.Element(nsABC + "xyz")
    }).ToList();

    foreach (ABC abc in abcs)
    {
        Debug.WriteLine($"ABC: '{abc.Asd}' XYZ: '{abc.Xyz}'");
    }
}

资源

评论

0赞 tanatan 2/2/2023
感谢您@user09938回复。我无法更改整个代码,因为它是现有代码,并且必须使用 XmlDocument 方法。我见过可能的例子。我认为我在 XMLNamespace 管理器中设置命名空间时做错了什么。
0赞 bgman 2/2/2023 #2

还可以执行此操作:复制 xml 并使用 Paste special -> Paste Xml as classes 将其粘贴到 Visual Studio 中。现在,您将拥有一个 Envelope 类,您可以像以下示例中一样反序列化 xml:https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer.deserialize?view=net-7.0。 Soap 消息可能非常复杂,使用对象会更容易,如果需要,您可以修改这些对象并最终序列化回来。

0赞 tanatan 2/2/2023 #3

谢谢你们的回复,但我设法解决了它。在 namsspace 管理器中,我进行了以下更改

nsmgr.AddNamespace("x", "http://xmlns.example.com/abc/a6/AB/XYZ/V1");

在列出 ABC 节点时,我进行了以下更改,即用 x 作为 ABC 的前缀:

XmlNodeList lst = responseDoc.SelectNodes("//x:ABC", nsmgr);

其余的代码保持原样,现在我可以遍历所有 ABC 节点。