Web Services XmlNodeList为空

py49o6xq  于 2023-01-21  发布在  其他
关注(0)|答案(1)|浏览(162)

我得到了这个xml。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" >
   <soapenv:Header/>
   <soapenv:Body>
      <GetSelectedModels xmlns="http://www.something/">
         <!--Optional:-->
         <input xmlns="http://www.something/">
            <X_Models>
            <ListOfModels>
               <Model>
                  <ModelId>163</ModelId>
               </Model>             
            </ListOfModels>
         </X_Models>
         </input>
      </GetSelectedModels>
   </soapenv:Body>
</soapenv:Envelope>

当我在SoapUi中发布它并且它到达我的Web服务时,我希望使用节点。

XmlDocument docRequest = new XmlDocument();
docRequest.LoadXml(xml);
XmlNodeList models= docRequest.SelectNodes("X_Models/ListOfModels/Model");

models为0,xml如下所示:

<X_Modelsxmlns="http://www.something/">
    <ListOfModels>
       <Model>
          <ModelID>163</ModelID>
       </Model>             
    </ListOfModelss>
 </X_Models>

如果我像这样使用别名发布xml:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:net="http://www.something/" >
  <soapenv:Header/>
  <soapenv:Body>
    <net:GetSelectedModels>
      <!--Optional:-->
      <net:input>
        <X_Models>
          <ListOfModels>
            <Model>
              <ModelId>163</ModelId>
            </Model>             
          </ListOfModels>
        </X_Models>
      </net:input>
    </net:GetSelectedModels>
  </soapenv:Body>
</soapenv:Envelope>

那么models将为1,xml如下所示:

<X_Models>
 <ListOfModels>
                    <Model>
                          <ModelID>163</ModelID>
                       </Model>             
                    </ListOfModelss>
                 </X_Models>

有谁能给我指出正确的方向吗?谢谢!

1wnzp6jl

1wnzp6jl1#

在第一种情况下,X_Models节点和所有后代都在默认名称空间xmlns="http://www.something/"中。在第二种情况下,没有默认名称空间,因此X_Models树不在任何名称空间中。
XmlNode.SelectNodes Method (String)的文档指定必须按如下方式处理默认名称空间:
如果XPath表达式不包含前缀,则假定命名空间URI为空命名空间。如果XML包含默认命名空间,则仍必须使用XmlNamespaceManager并向其添加前缀和命名空间URI;否则,您将无法选择任何节点。有关详细信息,请参阅Select Nodes Using XPath Navigation
因此,根据您在问题开始时显示的XML(与您的代码不完全匹配),您需要执行以下操作:

string xml = @"<?xml version=""1.0"" standalone=""no"" ?>
        <soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" >
           <soapenv:Header/>
           <soapenv:Body>
              <GetSelectedModels xmlns=""http://www.something/"">
                 <!--Optional:-->
                 <input xmlns=""http://www.something/"">
                    <X_Models>
                    <ListOfModels>
                       <Model>
                          <ModelId>163</ModelId>
                       </Model>             
                    </ListOfModels>
                 </X_Models>
                 </input>
              </GetSelectedModels>
           </soapenv:Body>
        </soapenv:Envelope>
        ";

    XmlDocument docRequest = new XmlDocument();
    docRequest.LoadXml(xml);

    XmlNamespaceManager ns = new XmlNamespaceManager(docRequest.NameTable);
    ns.AddNamespace("models", "http://www.something/");
    ns.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");

    XmlNodeList models = docRequest.SelectNodes("/soapenv:Envelope/soapenv:Body/models:GetSelectedModels/models:input/models:X_Models/models:ListOfModels/models:Model", ns);
    Debug.Assert(models.Count == 1);
    • 更新**

如果你真的想在XML层次结构上运行查询,而忽略名称空间,只使用本地名称,那么SelectNodes并不能做到这一点,你需要一些扩展方法,比如:

public static class XmlNodeExtensions
{
    public static IEnumerable<XmlElement> ChildElements(this IEnumerable<XmlElement> elements)
    {
        return elements.SelectMany(e => e.ChildNodes.OfType<XmlElement>());
    }

    public static IEnumerable<XmlElement> OfLocalName(this IEnumerable<XmlElement> elements, string localName)
    {
        return elements.Where(e => e.LocalName == localName);
    }
}

然后你可以做:

string xml1 = @"<?xml version=""1.0"" standalone=""no"" ?>
        <soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" >
           <soapenv:Header/>
           <soapenv:Body>
              <GetSelectedModels xmlns=""http://www.something/"">
                 <!--Optional:-->
                 <input xmlns=""http://www.something/"">
                    <X_Models>
                    <ListOfModels>
                       <Model>
                          <ModelId>163</ModelId>
                       </Model>             
                    </ListOfModels>
                 </X_Models>
                 </input>
              </GetSelectedModels>
           </soapenv:Body>
        </soapenv:Envelope>
        ";

    string xml2 = @"
        <soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:net=""http://www.something/"" >
           <soapenv:Header/>
           <soapenv:Body>
              <net:GetSelectedModels>
                 <!--Optional:-->
                 <net:input>
                    <X_Models>
                    <ListOfModels>
                       <Model>
                          <ModelId>163</ModelId>
                       </Model>             
                    </ListOfModels>
                 </X_Models>
                 </net:input>
              </net:GetSelectedModels>
           </soapenv:Body>
        </soapenv:Envelope>
        ";

    XmlDocument doc1 = new XmlDocument();
    doc1.LoadXml(xml1);

    XmlDocument doc2 = new XmlDocument();
    doc2.LoadXml(xml2);

    var ignoreNameSpaceModels1 = doc1.DocumentElement.ChildNodes.OfType<XmlElement>().OfLocalName("Body").ChildElements().OfLocalName("GetSelectedModels").ChildElements().OfLocalName("input").ChildElements().OfLocalName("X_Models").ToArray();
    var ignoreNameSpaceModels2 = doc2.DocumentElement.ChildNodes.OfType<XmlElement>().OfLocalName("Body").ChildElements().OfLocalName("GetSelectedModels").ChildElements().OfLocalName("input").ChildElements().OfLocalName("X_Models").ToArray();

    Debug.Assert(ignoreNameSpaceModels1.Length == 1 && ignoreNameSpaceModels2.Length == 1 && ignoreNameSpaceModels1[0].LocalName == "X_Models" && ignoreNameSpaceModels2[0].LocalName == "X_Models");

但这就像说typeof(System.Windows.Forms.RichTextBox) == typeof(System.Windows.Controls.RichTextBox)因为他们的Name是相同的。那是因为,xmlns="http://www.something/"属性在下面:

<GetSelectedModels xmlns="http://www.something/">
          <!--child elements... -->
      </GetSelectedModels>

表示"默认情况下,元素GetSelectedModels * 和所有子元素 * 属于命名空间http://www.something/"。

<net:GetSelectedModels>
          <!--child elements... -->
      </net:GetSelectedModels>

仅表示"元素GetSelectedModels属于命名空间http://www.something/"。它不适用于子元素。递归作用域是default namespace attribute的一个特殊属性。

相关问题