xml - guia - qgis manual
¿Cómo puedo dividir un documento XML en tres partes(o, mejor aún, n piezas)? (10)
Me gustaría utilizar un lenguaje con el que estoy familiarizado: Java, C #, Ruby, PHP, C / C ++, aunque los ejemplos en cualquier idioma o pseudocódigo son más que bienvenidos.
¿Cuál es la mejor manera de dividir un documento XML grande en secciones más pequeñas que siguen siendo XML válido? Para mis propósitos, necesito dividirlos en aproximadamente tres tercios o cuartos, pero para dar ejemplos, dividirlos en n componentes sería bueno.
Bueno, por supuesto, siempre puede extraer los elementos de nivel superior (si esta es la granularidad que desea, depende de usted). En C #, usarías la clase XmlDocument. Por ejemplo, si su archivo XML se ve así:
<Document>
<Piece>
Some text
</Piece>
<Piece>
Some other text
</Piece>
</Document>
entonces usarías un código como este para extraer todas las Piezas:
XmlDocument doc = new XmlDocument();
doc.Load("<path to xml file>");
XmlNodeList nl = doc.GetElementsByTagName("Piece");
foreach (XmlNode n in nl)
{
// Do something with each Piece node
}
Una vez que tiene los nodos, puede hacer algo con ellos en su código, o puede transferir todo el texto del nodo a su propio documento XML y actuar sobre eso como si fuera una pieza independiente de XML (incluido guardarlo). volver al disco, etc.).
Como DannySmurf toca aquí, se trata de la estructura del documento xml.
Si solo tiene dos enormes etiquetas de "nivel superior", será extremadamente difícil poder dividirlo de manera que sea posible fusionarlo de nuevo y leerlo pieza por pieza como xml válido.
Dado un documento con muchas piezas separadas como las del ejemplo de DannySmurfs, debería ser bastante fácil.
Algún código aproximado en Pseudo C #:
int nrOfPieces = 5;
XmlDocument xmlOriginal = some input parameter..
// construct the list we need, and fill it with XmlDocuments..
var xmlList = new List<XmlDocument>();
for (int i = 0; i < nrOfPieces ; i++)
{
var xmlDoc = new XmlDocument();
xmlDoc.ChildNodes.Add(new XmlNode(xmlOriginal.FistNode.Name));
xmlList.Add(xmlDoc);
}
var nodeList = xmlOriginal.GetElementsByTagName("Piece")M
// Copy the nodes from the original into the pieces..
for (int i = 0; i < nodeList .Count; i++)
{
var xmlDoc = xmlList[i % nrOfPieces];
var nodeToCopy = nodeList[i].Clone();
xmlDoc.FirstNode.ChildNodes.Add(nodeToCopy);
}
Esto debería darle n documentos con el xml correcto y la posibilidad de fusionarlos nuevamente.
Pero, de nuevo, depende del archivo xml.
Esto es más un comentario que una respuesta, pero no:
XmlDocument doc = new XmlDocument();
doc.Load("path");
¿Leer todo el archivo a la vez? Solo pensé que debería plantear el punto ya que, a juzgar por la pregunta de Thomas, le preocupa leer archivos de gran tamaño y quiere romper el proceso.
No estoy seguro de qué tipo de procesamiento está haciendo, pero para XML muy grande, siempre he sido un fanático del procesamiento basado en eventos. Tal vez es mi experiencia en Java, pero realmente me gusta SAX. Necesita hacer su propia administración de estado, pero una vez que lo supera, es un método muy eficiente de analizar XML.
Si no eres completamente alérgico a Perl, entonces XML :: Twig viene con una herramienta llamada xml_split que puede dividir un documento, produciendo una sección XML bien formada. Puede dividir en un nivel del árbol, por tamaño o en una expresión XPath.
Voy a ir con youphoric en este caso. Para archivos muy grandes, SAX (o cualquier otro analizador de transmisión) será de gran ayuda en el procesamiento. Usando DOM puedes recolectar solo nodos de nivel superior, pero aún tienes que analizar todo el documento para hacerlo ... usando un analizador de flujo continuo y el procesamiento basado en eventos te permite "omitir" los nodos que no te interesan; hace que el procesamiento sea más rápido.
Hice un video de YouTube que muestra cómo dividir archivos XML con foxe (el editor XML gratuito de Firstobject ) utilizando solo una pequeña cantidad de memoria, independientemente del tamaño de los archivos de entrada y salida.
El uso de memoria para este lector de CMarkup XML (analizador de pull) y la solución de escritor XML depende del tamaño de los subdocumentos que se transfieren individualmente desde el archivo de entrada a los archivos de salida, o del tamaño de bloque mínimo de 16 KB.
split() { CMarkup xmlInput, xmlOutput; xmlInput.Open( "50MB.xml", MDF_READFILE ); int nObjectCount = 0, nFileCount = 0; while ( xmlInput.FindElem("//ACT") ) { if ( nObjectCount == 0 ) { ++nFileCount; xmlOutput.Open( "piece" + nFileCount + ".xml", MDF_WRITEFILE ); xmlOutput.AddElem( "root" ); xmlOutput.IntoElem(); } xmlOutput.AddSubDoc( xmlInput.GetSubDoc() ); ++nObjectCount; if ( nObjectCount == 5 ) { xmlOutput.Close(); nObjectCount = 0; } } if ( nObjectCount ) xmlOutput.Close(); xmlInput.Close(); return nFileCount; }
Leería todo el archivo a la vez. En mi experiencia, sin embargo, si solo estás leyendo el archivo, haciendo algún procesamiento (es decir, dividiéndolo) y luego continuando con tu trabajo, XmlDocument pasará por su ciclo de creación / lectura / recopilación tan rápido que es probable que no importe.
Por supuesto, eso depende de qué es un archivo "grande". Si se trata de un archivo XML de 30 MB (que consideraría grande para un archivo XML), probablemente no haga ninguna diferencia. Si se trata de un archivo XML de 500 MB, el uso de XmlDocument se volverá extremadamente problemático en sistemas sin una cantidad significativa de RAM (en ese caso, sin embargo, argumentaría que el tiempo para seleccionar manualmente el archivo con un XmlReader sería el más significativo impedimento).
Parece que estás trabajando con C # y .NET 3.5. Me he encontrado con algunas publicaciones que sugieren utilizar un tipo de algoritmo de rendimiento en una secuencia de archivos con un XmlReader.
Aquí hay un par de publicaciones en el blog para que comiences por el camino:
Analizar documentos XML usando DOM no escala.
Este Groovy -script está usando StAX (Streaming API for XML) para dividir un documento XML entre los elementos de nivel superior (que comparte el mismo QName que el primer elemento secundario del documento raíz). Es bastante rápido, maneja documentos grandes arbitrarios y es muy útil cuando se quiere dividir un gran archivo por lotes en partes más pequeñas.
Requiere Groovy en Java 6 o una API StAX e implementación como Woodstox en CLASSPATH
import javax.xml.stream.*
pieces = 5
input = "input.xml"
output = "output_%04d.xml"
eventFactory = XMLEventFactory.newInstance()
fileNumber = elementCount = 0
def createEventReader() {
reader = XMLInputFactory.newInstance().createXMLEventReader(new FileInputStream(input))
start = reader.next()
root = reader.nextTag()
firstChild = reader.nextTag()
return reader
}
def createNextEventWriter () {
println "Writing to ''${filename = String.format(output, ++fileNumber)}''"
writer = XMLOutputFactory.newInstance().createXMLEventWriter(new FileOutputStream(filename), start.characterEncodingScheme)
writer.add(start)
writer.add(root)
return writer
}
elements = createEventReader().findAll { it.startElement && it.name == firstChild.name }.size()
println "Splitting ${elements} <${firstChild.name.localPart}> elements into ${pieces} pieces"
chunkSize = elements / pieces
writer = createNextEventWriter()
writer.add(firstChild)
createEventReader().each {
if (it.startElement && it.name == firstChild.name) {
if (++elementCount > chunkSize) {
writer.add(eventFactory.createEndDocument())
writer.flush()
writer = createNextEventWriter()
elementCount = 0
}
}
writer.add(it)
}
writer.flush()