2008-12-17 10 views
6

Llamo a un servicio web expuesto por Oracle que acepta una entrada de un ID de elemento y me devuelve el número de artículo correspondiente. Quiero obtener el Número de artículo que se ha devuelto del XML contenido en la respuesta.¿Cuál es una buena manera de encontrar un valor específico en un documento XML usando C#?

El XML tiene el siguiente aspecto:

<env:Envelope 
    xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:ns0="http://dev1/MyWebService1.wsdl"> 
<env:Header> 
    <wsse:Security 
    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
    xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
    xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" 
    env:mustUnderstand="1"/> 
</env:Header> 
<env:Body> 
    <ns0:getItemNbrByItemIdResponseElement> 
    <ns0:result>1010603</ns0:result> 
    </ns0:getItemNbrByItemIdResponseElement> 
</env:Body> 
</env:Envelope> 

Estoy interesado en agarrar sólo el <ns0:result>1010603</ns0:result> particular sólo el 1010603.

no he hecho mucho trabajo analizar XML usando C# y yo Estoy jugando con algunos métodos diferentes hasta ahora. cual es la manera recomendada para hacer esto?

Estoy en VS2008 (por lo XPath está disponible, etc.)

Respuesta

15

que haría uso personal LINQ to XML, porque me parece que más fácil de tratar que XPath, sobre todo cuando se trata de espacios de nombres. Se podría hacer algo como:

XNamespace ns0 = "http://dev1/MyWebService1.wsdl"; 

String result = doc.Descendants(ns0 + "result").First().Value; 

Tenga en cuenta que doc aquí se espera que sea un XDocument, no un XmlDocument. (. Mi conjetura es que esto es por qué no se muestra para usted)

+0

De acuerdo; sin LINQ necesitarías usar namespace-managers y todo tipo de cosas, esto es mucho más simple. –

+0

"necesita" es una palabra fuerte :) – annakata

+0

+1, los espacios de nombres "necesitan" ser más fáciles de trabajar que XLINQ funciona bien – user7116

2

De la parte superior de mi cabeza, lo siguiente debe funcionar:

XmlDocument doc = new XmlDocument(); 
doc.PreserveWhitespace = true; 

XmlNamespaceManager mgr = GetNamespace(doc); 
doc.LoadXml(xmltext); 

XmlNode nd = doc.DocumentElement.SelectSingleNode("//ns0:result", mgr); 

El código de espacio de nombres tiene este aspecto:

private XmlNamespaceManager GetNamespace(XmlDocument document) 
{ 
    XmlNamespaceManager mgr = new XmlNamespaceManager(document.NameTable); 
    mgr.AddNamespace("ns0", "http://dev1/MyWebService1.wsdl"); 
    return mgr; 
} 

Debe usar el administrador del espacio de nombres porque el documento XML tiene espacios de nombres asociados, y XPath lo usa en resolución de consulta.

+0

Eso está cerca ... Acabo de probarlo y me está dando un error: Namespace Manager o XsltContext necesarios. Esta consulta tiene un prefijo, variable o función definida por el usuario. –

+0

Es malo: el SelectSingleNode debería tener una referencia al administrador del espacio de nombres. Lo actualizaré. –

+0

¡Gracias por la solución! :) ¡Podría mejorar mi juego y aprender algunas cosas y entonces no tendrías que resolver mis problemas por mí! ;) –

3

Si no desea ir para LINQ podría utilizar XPathDocument para recuperar el valor:

XPathDocument xmldoc = new XPathDocument(@"C:\tmp\sample.xml"); 
XPathNavigator nav = xmldoc.CreateNavigator(); 

XmlNamespaceManager nsMgr = new XmlNamespaceManager(nav.NameTable); 
nsMgr.AddNamespace("ns0", "http://dev1/MyWebService1.wsdl"); 

XPathNavigator result = nav.SelectSingleNode("//ns0:result", nsMgr); 
System.Diagnostics.Debug.WriteLine(result.Value); 

XPathDocument tiene una huella de memoria más baja y es más probable más rápido en su escenario de XmlDocument. XmlDocument crea un modelo de objeto completo de su documento XML en memoria, mientras que XPathDocument no lo hace.

+0

Este funciona bastante bien. :) ¡Gracias por la publicacion! –

5

fwiw se puede engañar al problema de espacio de nombres con un XPath como esto: //*[local-name()='result']

+0

esto es mucho más elegante que la respuesta elegida. –

0

Hay muy buenas y completas respuestas a esta pregunta.

Yo añadiría sólo por curiosidad, que una expresión XPath extremadamente simple hace el trabajo en este caso particular:

      normalize-space(/)

Esto se hace fácilmente en C# usando algo así como las dos líneas a continuación:

 XPathNavigator navigator = document.CreateNavigator(); 

     string res = (string)navigator.Evaluate("normalize-space(/)"); 

Con la g Una buena optimización del motor .NET XPath, su evaluación puede ser incluso eficiente.

1

Para resolver esto, utilicé la respuesta de Jon Skeet. Este es el código que tuve que implementar para que esto funcione (para el beneficio futuro de cualquier otra persona).

XmlDocument xmlDoc = new XmlDocument(); 

XNamespace ns0 = "http://dev1/MyWebService1.wsdl"; 

xmlDoc.Load(request.GetResponse().GetResponseStream()); 

XDocument xDoc = XDocument.Load(new XmlNodeReader(xmlDoc));       

String result = xDoc.Descendants(ns0 + "result").First().Value; 

supuesto, esto supone que estoy recibiendo mi respuesta de nuevo a partir de una HttpWebRequest llamado solicitud.

Cuestiones relacionadas