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.