read nodo manejo leer especifico ejemplos atributos c# xml xmlreader

nodo - Lectura de Xml con XmlReader en C#



xmldocument (7)

El siguiente ejemplo navega por la ruta para determinar el tipo de nodo actual y luego usa XmlWriter para generar el contenido de XmlReader.

StringBuilder output = new StringBuilder(); String xmlString = @"<?xml version=''1.0''?> <!-- This is a sample XML document --> <Items> <Item>test with a child element <more/> stuff</Item> </Items>"; // Create an XmlReader using (XmlReader reader = XmlReader.Create(new StringReader(xmlString))) { XmlWriterSettings ws = new XmlWriterSettings(); ws.Indent = true; using (XmlWriter writer = XmlWriter.Create(output, ws)) { // Parse the file and display each of the nodes. while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: writer.WriteStartElement(reader.Name); break; case XmlNodeType.Text: writer.WriteString(reader.Value); break; case XmlNodeType.XmlDeclaration: case XmlNodeType.ProcessingInstruction: writer.WriteProcessingInstruction(reader.Name, reader.Value); break; case XmlNodeType.Comment: writer.WriteComment(reader.Value); break; case XmlNodeType.EndElement: writer.WriteFullEndElement(); break; } } } } OutputTextBlock.Text = output.ToString();

El siguiente ejemplo usa los métodos XmlReader para leer el contenido de los elementos y atributos.

StringBuilder output = new StringBuilder(); String xmlString = @"<bookstore> <book genre=''autobiography'' publicationdate=''1981-03-22'' ISBN=''1-861003-11-0''> <title>The Autobiography of Benjamin Franklin</title> <author> <first-name>Benjamin</first-name> <last-name>Franklin</last-name> </author> <price>8.99</price> </book> </bookstore>"; // Create an XmlReader using (XmlReader reader = XmlReader.Create(new StringReader(xmlString))) { reader.ReadToFollowing("book"); reader.MoveToFirstAttribute(); string genre = reader.Value; output.AppendLine("The genre value: " + genre); reader.ReadToFollowing("title"); output.AppendLine("Content of the title element: " + reader.ReadElementContentAsString()); } OutputTextBlock.Text = output.ToString();

Intento leer el siguiente documento Xml lo más rápido que puedo y permitir que otras clases administren la lectura de cada subbloque.

<ApplicationPool> <Accounts> <Account> <NameOfKin></NameOfKin> <StatementsAvailable> <Statement></Statement> </StatementsAvailable> </Account> </Accounts> </ApplicationPool>

Sin embargo, estoy tratando de usar el objeto XmlReader para leer cada cuenta y, posteriormente, el "StatementsAvailable". ¿Sugiere usar XmlReader.Read y comprobar cada elemento y manejarlo?

He pensado en separar mis clases para manejar cada nodo correctamente. Entonces hay una clase AccountBase que acepta una instancia de XmlReader que lee el NameOfKin y varias otras propiedades sobre la cuenta. Luego quería intervenir a través de los enunciados y dejar que otra clase se completara con la Declaración (y luego la agregue a un IList).

Hasta ahora tengo la parte "por clase" hecha al hacer XmlReader.ReadElementString (), pero no puedo entrenar cómo decirle al puntero que se mueva al elemento StatementsAvailable y permitirme iterar a través de ellos y dejar que otra clase lea cada una de esas proeprties .

¡Suena fácil!


Hacemos este tipo de análisis XML todo el tiempo. La clave es definir dónde el método de análisis dejará al lector al salir. Si siempre deja el lector en el siguiente elemento que sigue al elemento que se leyó por primera vez, puede leer de manera segura y predecible en la secuencia XML. Por lo tanto, si el lector indexa actualmente el elemento <Account> , después de analizar el lector indexará la etiqueta de cierre </Accounts> .

El código de análisis se ve así:

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; } } } }

La clase de Statements solo se lee en el nodo <StatementsAvailable>

public class Statements { List<Statement> _statements = new List<Statement>(); 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; } } } }

La clase Statement 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 } } }


Mi experiencia con XmlReader es que es muy fácil leer demasiado accidentalmente. Sé que has dicho que quieres leerlo lo más rápido posible, pero ¿has intentado usar un modelo DOM en su lugar? Descubrí que LINQ to XML hace que XML funcione mucho más fácilmente.

Si su documento es particularmente enorme, puede combinar XmlReader y LINQ a XML creando un XElement de un XmlReader para cada uno de sus elementos "externos" de forma continua: esto le permite hacer la mayor parte del trabajo de conversión en LINQ a XML, pero todavía solo necesita una pequeña porción del documento en la memoria en cualquier momento. Aquí hay un código de muestra (ligeramente adaptado de esta publicación de blog ):

static IEnumerable<XElement> 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; } } } } } }

Lo he usado para convertir los datos de usuario de (que es enorme) en otro formato anterior, funciona muy bien.

EDIT desde radarbob, reformateado por Jon - aunque no está del todo claro a qué problema de "leer demasiado" se está haciendo referencia ...

Esto debería simplificar el anidamiento y resolver el problema de "leer demasiado".

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 "leer demasiado" porque implementa el patrón de ciclo while clásico:

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


No soy experimentado. Pero creo que XmlReader es innecesario. Es muy difícil de usar.
XElement es muy fácil de usar.
Si necesita rendimiento (más rápido), debe cambiar el formato de archivo y usar las clases StreamReader y StreamWriter.


Para los subobjetos, ReadSubtree() le proporciona un lector xml limitado a los subobjetos, pero realmente creo que lo está haciendo de la manera difícil. A menos que tenga requisitos muy específicos para manejar xml inusual / impredecible, use XmlSerializer (tal vez junto con sgen.exe si realmente lo desea).

XmlReader es ... complicado. Contraste a:

using System; using System.Collections.Generic; using System.Xml.Serialization; public class ApplicationPool { private readonly List<Account> accounts = new List<Account>(); public List<Account> Accounts {get{return accounts;}} } public class Account { public string NameOfKin {get;set;} private readonly List<Statement> statements = new List<Statement>(); public List<Statement> StatementsAvailable {get{return statements;}} } public class Statement {} static class Program { static void Main() { XmlSerializer ser = new XmlSerializer(typeof(ApplicationPool)); ser.Serialize(Console.Out, new ApplicationPool { Accounts = { new Account { NameOfKin = "Fred", StatementsAvailable = { new Statement {}, new Statement {}}}} }); } }


Tres años después, tal vez con el énfasis renovado en los datos de WebApi y xml, me encontré con esta pregunta. Como en sentido de código me inclino a seguir a Skeet desde un avión sin paracaídas, y al ver su código inicial doblemente corraborado por el artículo del equipo MS Xml y un ejemplo en BOL Streaming Transform de 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 estaban analizando documentos de origen con elementos de destino anidados más allá del 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 el momento, y toma en cuenta que el xml puede provenir de diferentes fuentes, no solo de un uri, y entonces la extensión funciona en el XmlReader administrado por el usuario. La única suposición es que el lector se encuentra en su estado inicial, ya que de lo contrario la primera ''Lectura ()'' podría avanzar más allá de un nodo deseado:

public static IEnumerable<XElement> 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(); } }


XmlDataDocument xmldoc = new XmlDataDocument(); XmlNodeList xmlnode ; int i = 0; string str = null; FileStream fs = new FileStream("product.xml", FileMode.Open, FileAccess.Read); xmldoc.Load(fs); xmlnode = xmldoc.GetElementsByTagName("Product");

Puede recorrer el xmlnodo y obtener los datos ... C # Reader XML