Saltar al contenido

Leer XML con XmlReader en C #

Este team de especialistas pasados varios días de trabajo y recopilar de datos, dieron con la respuesta, esperamos que te sea útil para tu plan.

Solución:

Mi experiencia de XmlReader es que es muy fácil leer demasiado accidentalmente. Sé que ha dicho que quiere leerlo lo más rápido posible, pero intentó usando un modelo DOM en su lugar? Descubrí que LINQ to XML hace que XML funcione mucho mucho más fácil.

Si su documento es particularmente grande, puede combinar XmlReader y LINQ to XML creando un XElement desde un XmlReader para cada uno de sus elementos “externos” en forma de transmisión: esto le permite hacer la mayor parte del trabajo de conversión en LINQ a XML, pero aún necesita solo una pequeña parte del documento en la memoria a la vez. Aquí hay un código de muestra (adaptado ligeramente de esta publicación de blog):

static IEnumerable SimpleStreamAxis(string inputUrl,
                                              string elementName)

  using (XmlReader reader = XmlReader.Create(inputUrl))
  
    reader.MoveToContent();
    while (reader.Read())
    
      if (reader.NodeType == XmlNodeType.Element)
      
        if (reader.Name == elementName)
        
          XElement el = XNode.ReadFrom(reader) as XElement;
          if (el != null)
          
            yield return el;
          
        
      
    
  

He usado esto para convertir los datos del usuario de StackOverflow (que es enorme) a otro formato antes; funciona muy bien.

EDITAR desde radarbob, reformateado por Jon, aunque no está del todo claro a qué problema de “lectura demasiado lejos” se hace referencia …

Esto debería simplificar el anidamiento y solucionar el problema de “una lectura demasiado lejana”.

using (XmlReader reader = XmlReader.Create(inputUrl))

    reader.ReadStartElement("theRootElement");

    while (reader.Name == "TheNodeIWant")
    
        XElement el = (XElement) XNode.ReadFrom(reader);
    

    reader.ReadEndElement();

Esto soluciona el problema de “una lectura demasiado lejana” porque implementa el patrón de bucle while clásico:

initial read;
(while "we're not at the end") 
    do stuff;
    read;

Tres años más tarde, tal vez con el énfasis renovado en WebApi y los datos xml, me encontré con esta pregunta. Dado que, según el código, me inclino a seguir a Skeet fuera de un avión sin paracaídas, y al ver su código inicial doblemente corraborado por el artículo del equipo MS Xml, así como un ejemplo en BOL Streaming Transform of Large Xml Docs, rápidamente pasé por alto los otros comentarios. , más específicamente de ‘pbz’, quien señaló que si tiene los mismos elementos por nombre en sucesión, todos los demás se omiten debido a la doble lectura. Y, de hecho, los artículos de blog de BOL y MS analizaban documentos de origen con elementos de destino anidados más profundos que el segundo nivel, enmascarando este efecto secundario.

Las otras respuestas abordan este problema. Solo quería ofrecer una revisión un poco más simple que parece funcionar bien hasta ahora y tiene en cuenta que el xml puede provenir de diferentes fuentes, no solo un uri, por lo que la extensión funciona en el XmlReader administrado por el usuario. La única suposición es que el lector está en su estado inicial, ya que de lo contrario el primer ‘Read ()’ podría avanzar más allá de un nodo deseado:

public static IEnumerable ElementsNamed(this XmlReader reader, string elementName)

    reader.MoveToContent(); // will not advance reader if already on a content node; if successful, ReadState is Interactive
    reader.Read();          // this is needed, even with MoveToContent and ReadState.Interactive
    while(!reader.EOF && reader.ReadState == ReadState.Interactive)
    
        // corrected for bug noted by Wes below...
        if(reader.NodeType == XmlNodeType.Element && reader.Name.Equals(elementName))
        
             // this advances the reader...so it's either XNode.ReadFrom() or reader.Read(), but not both
             var matchedElement = XNode.ReadFrom(reader) as XElement;
             if(matchedElement != null)
                 yield return matchedElement;
        
        else
            reader.Read();
    

Hacemos este tipo de análisis XML todo el tiempo. los key es definir dónde el método de análisis dejará al lector al salir. Si siempre deja al lector en el siguiente elemento que sigue al elemento que se leyó primero, entonces puede leer de manera segura y predecible en el flujo XML. Entonces, si el lector está indexando elemento, después de analizar, el lector indexará el etiqueta de cierre.

El código de análisis se parece a esto:

public class Account

    string _accountId;
    string _nameOfKin;
    Statements _statmentsAvailable;

    public void ReadFromXml( XmlReader reader )
    
        reader.MoveToContent();

        // Read node attributes
        _accountId = reader.GetAttribute( "accountId" );
        ...

        if( reader.IsEmptyElement )  reader.Read(); return; 

        reader.Read();
        while( ! reader.EOF )
        
            if( reader.IsStartElement() )
            
                switch( reader.Name )
                
                    // Read element for a property of this class
                    case "NameOfKin":
                        _nameOfKin = reader.ReadElementContentAsString();
                        break;

                    // Starting sub-list
                case "StatementsAvailable":
                    _statementsAvailable = new Statements();
                    _statementsAvailable.Read( reader );
                    break;

                    default:
                        reader.Skip();
                
            
            else
            
                reader.Read();
                break;
            
               
    

los Statements la clase solo lee en el nodo

public class Statements

    List _statements = new List();

    public void ReadFromXml( XmlReader reader )
    
        reader.MoveToContent();
        if( reader.IsEmptyElement )  reader.Read(); return; 

        reader.Read();
        while( ! reader.EOF )
        
            if( reader.IsStartElement() )
            
                if( reader.Name == "Statement" )
                
                    var statement = new Statement();
                    statement.ReadFromXml( reader );
                    _statements.Add( statement );               
                
                else
                
                    reader.Skip();
                
            
            else
            
                reader.Read();
                break;
            
        
    

los Statement la clase se vería muy parecida

public class Statement

    string _satementId;

    public void ReadFromXml( XmlReader reader )
    
        reader.MoveToContent();

        // Read noe attributes
        _statementId = reader.GetAttribute( "statementId" );
        ...

        if( reader.IsEmptyElement )  reader.Read(); return; 

        reader.Read();
        while( ! reader.EOF )
                   
            ....same basic loop
               
    

Comentarios y puntuaciones

Al final de todo puedes encontrar las aclaraciones de otros programadores, tú de igual forma tienes la libertad de mostrar el tuyo si lo crees conveniente.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *