2010-11-29 18 views
11

Esto no parece que debería ser difícil, pero estoy atascado actualmente. Estoy tratando de obtener los valores de atributo para un atributo particular de los nodos que coinciden con una cadena de consulta XPath determinada. Esto es lo que tengo hasta ahora:Obtiene valores de atributo de nodos XML coincidentes utilizando la consulta XPath

public static IEnumerable<string> GetAttributes(this XmlDocument xml, 
     string xpathQuery, string attributeName) 
    { 
     var doc = new XPathDocument(new XmlNodeReader(xml)); 
     XPathNavigator nav = doc.CreateNavigator(); 
     XPathExpression expr = nav.Compile(xpathQuery); 
     XPathNodeIterator iterator = nav.Select(expr); 
     while (iterator.MoveNext()) 
     { 
      XPathNavigator curNav = iterator.Current; 
      if (curNav.HasAttributes) 
      { 
       XmlNode curNode = ((IHasXmlNode)curNav).GetNode(); 
       if (null != curNode) 
       { 
        XmlAttribute attrib = curNode.Attributes[attributeName]; 
        if (null != attrib) 
        { 
         yield return attrib.Value; 
        } 
       } 
      } 
     } 
    } 

Esto arroja actualmente una excepción:

System.InvalidCastException: No se puede convertir objeto de tipo 'MS.Internal.Xml.Cache.XPathDocumentNavigator' escribir ' System.Xml.IHasXmlNode '.

¿Estoy yendo sobre esto mal? ¿Hay alguna forma más sencilla de obtener los valores de los atributos de los nodos coincidentes?

+1

¿Por qué no utilizar LinqToXml? Esto reduciría considerablemente el ruido, a menos que me falte alguna razón por la que no puedas hacer esto con Linq. –

Respuesta

31

para el siguiente xml:

<root> 
    <elem att='the value' /> 
</root> 

, usted puede obtener el texto "el valor" con este código C#

XmlDocument xdoc = new XmlDocument(); 
    xdoc.LoadXml(text); 
    Console.WriteLine(xdoc.SelectSingleNode("/root/elem/@att").Value); 
+0

Derp. Había visto 'SelectNodes' como un método en un' XmlElement', como 'xmlDoc.DocumentElement', pero no pensé en verificar' XmlDocument'. Usar tu ejemplo pero con 'SelectNodes' funciona para mí. –

+0

+1 Buena respuesta. –

4

Si está utilizando .NET 3.5 o posterior se podría utilizar LINQ a XML

para un documento XML en cuestión

<?xml version="1.0" encoding="utf-8" ?> 
<root> 
    <storedProcedures> 
    <storedProcedure name="usp_GET_HOME_PAGE_DATA"> 
     <resultSet name="Features"/> 
     <resultSet name="Highlights"/> 
    </storedProcedure> 
    <storedProcedure name="usp_GET_FEATURES" /> 
    <storedProcedure name="usp_GET_FEATURE" /> 
    <storedProcedure name="usp_UPDATE_FEATURE" /> 
    <storedProcedure name="usp_GET_FEATURE_FOR_DISPLAY"> 
     <resultSet name="CurrentFeature"/> 
     <resultSet name="OtherFeatures"/> 
    </storedProcedure> 
    <storedProcedure name="usp_GET_HIGHLIGHT_TITLES"> 
     <resultSet name="Highlights"/> 
    </storedProcedure> 
    </storedProcedures> 
</root> 

La siguiente expresión LINQ le conseguirá los valores del "nombre" atributos de todos los nodos StoredProcedure

XDocument xDcoument = XDocument.Load(xmlStoredProcSchemeFile); 

    var storedProcedureNames = from doc in xDcoument.Descendants("storedProcedure") 
          select doc.Attribute("name").Value; 

también se puede utilizar la sintaxis XPath regular. En el código siguiente, el nodo variable contiene el nodo identificado por el nombre "usp_GET_HOME_PAGE_DATA" y luego la variable de atributos contiene todos los nodos secundarios (los atributos) del nodo seleccionado y sus elementos secundarios.

XmlDocument xmlDocument = new XmlDocument(); 
    xmlDocument.Load(@"C:\inetpub\wwwroot\ASPNETBuilder\BusinessLayer\DataAccessCodeGenerationSchema.xml"); 
    var node = xmlDocument.DocumentElement.SelectSingleNode("./storedProcedures/storedProcedure[@name='usp_GET_HOME_PAGE_DATA']"); 
    var attributes = node.SelectNodes("./resultSet/@name"); 
+4

"Deberías descartar totalmente eso y usar jQuery" –

+0

¿De qué estás hablando? Esto está en el lado del servidor o en un cliente GUI. ¿De dónde sacas Javascript/jQuery? –

+2

Compruebe http://meta.stackexchange.com/questions/19478/the-many-memes-of-meta/19492#19492 **;) ** –

1

solución al problema inicial de la excepción de ser lanzado ...

var doc = new XPathDocument(new XmlNodeReader(xml)); 

debe sustituirse por ...

var doc = new XmlDocument(); 
doc.load(*you can either specify the path to the file, the string out of which the xml document is to be generated or specify an xmlreader, look for more overloads*); 

esto no va a emitir la excepción y el código funcionará bien

Cuestiones relacionadas