我无法在 C#.Net 的 SOAP header 中正确 select 一个 XML 节点

I can't properly select an XML node in a SOAP header in C#.Net

我有一个 XML 文档封装在 SOAP header 中,但我不能 select 单个节点。我想我只是误解了当节点前面有文本时如何表示树。例如wsu:Timestamp、wsu:Created

这是我的 XML 的顶部部分:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:itk="urn:nhs-itk:ns:201005">
    <soap:Header>
        <wsa:MessageID>39c6f52b-1be0-42a9-a219-5d6ececd1695</wsa:MessageID>
        <wsa:Action>urn:nhs-itk:services:201005:SendCDADocument-v2-0</wsa:Action>
        <wsa:To>http://127.0.0.1:4000/syncsoap</wsa:To>
        <wsa:From>
            <wsa:Address>http://localhost</wsa:Address>
        </wsa:From>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="D6CD5232-14CF-11DF-9423-1F9A910D4703">
                <wsu:Created>2015-01-30T19:40:00</wsu:Created>
                <wsu:Expires>2015-01-30T19:50:00</wsu:Expires>
            </wsu:Timestamp>
            <wsse:UsernameToken>
                <wsse:Username>TKS Server test</wsse:Username>
            </wsse:UsernameToken>
        </wsse:Security>
    </soap:Header>

这是我的代码,它在 Select 单个节点上抛出空指针异常,因为它 return 不匹配。

private static XmlDocument CreateSoapEnvelope()
{
    XmlDocument soapEnvelop = new XmlDocument();
    DateTime myCreatedDate = DateTime.UtcNow;


    soapEnvelop.Load(@“c:\myFile.xml");
    soapEnvelop.SelectSingleNode("/soap/Envelope/Header/wsse/Security/wsu/Timestamp/Created").InnerText = myCreatedDate.ToString("yyyy-MM-ddTHH:mm:ssZ");
    return soapEnvelop;
}

我对区分大小写进行了三重检查,没有发现任何错误。当我放置一个断点时,我可以看到 XML 被加载到 soapEnvelop object 中。

我实施了使用命名空间管理器的建议,我可以 select 几个节点。但是,我在匹配 wsu:Timestamp 中的 Id 值时遇到问题。我尝试了以下但都无法匹配:

soapEnvelop.SelectSingleNode("//soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp/Id", ns).InnerText = Guid.NewGuid().ToString();
soapEnvelop.SelectSingleNode("//soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp/wsu:Id", ns).InnerText = Guid.NewGuid().ToString();
soapEnvelop.SelectSingleNode("//soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp", ns).Attributes["Id"].Value = Guid.NewGuid().ToString();

我解决了我的最后一个问题。如果您有一个空属性,则 Value() 调用必须 "fail"。当我在下面建议的代码中添加并取出现有 ID 并将其替换为“”时,我修改了我正在使用的 xml 文档,这就是我对 Created 和 Expires 所做的。问题一定是您可以为空字符串的节点设置 InnerText,但不能为属性设置它。也许这被认为是无效的 XML 所以 .Net 说 "no go dude".

奇怪的是,当我在初始设置 Id 之前更改我的代码以执行此调用时。

XmlNode myNode = soapEnvelop.SelectSingleNode("//soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp", ns);
myNode.Attributes["wsu:Id"].Value = Guid.NewGuid().ToString();

即使我的 xml 文件中的 Id 为“”,它也可以很好地设置值。这就是我偶然发现我的解决方案的方式,因为我将原始调用留在代码中并且它没有抛出异常所以它让我想到唯一的区别是 Id 有一个值。

谢谢, 旦

这是命名空间问题。您选择的节点并不都属于同一个命名空间,因此实际上无法访问它们。您需要使用 XmlNameSpaceManager 来存储您的命名空间并指定每个元素属于哪个命名空间。

如:

    private static XmlDocument CreateSoapEnvelope()
    {
        XmlDocument soapEnvelop = new XmlDocument();
        DateTime myCreatedDate = DateTime.UtcNow;


        soapEnvelop.Load(@"c:\myFile.xml");

        XmlNamespaceManager ns = new XmlNamespaceManager(soapEnvelop.NameTable);
        ns.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
        ns.AddNamespace("wsa", "http://www.w3.org/2005/08/addressing");
        ns.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
        ns.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

        soapEnvelop.SelectSingleNode("//soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp/wsu:Created", ns).InnerText = myCreatedDate.ToString("yyyy-MM-ddTHH:mm:ssZ");

    }

有更优雅的方法来执行此任务,但这至少可以让您继续。