2008-08-11 31 views
7

Me gustaría utilizar un lenguaje que conozco: Java, C#, Ruby, PHP, C/C++, aunque los ejemplos en cualquier idioma o pseudocódigo son más que bienvenidos.¿Cómo puedo dividir un documento XML en tres partes (o, mejor aún, n partes)?

¿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.

Respuesta

3

Bueno, por supuesto, siempre puede extraer los elementos de nivel superior (esta depende de la granularidad que desee). En C#, usarías la clase XmlDocument. Por ejemplo, si el archivo XML se veía algo como esto:

<Document> 
    <Piece> 
    Some text 
    </Piece> 
    <Piece> 
    Some other text 
    </Piece> 
</Document> 

entonces tendrá que utilizar 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 tienes 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 de nuevo en el disco, etc.).

1

Esto es más de un comentario de una respuesta, pero no quiso,

XmlDocument doc = new XmlDocument(); 
doc.Load("path"); 

leer todo el archivo a la vez? Solo pensé que debería plantear el punto ya que, según la pregunta de Thomas, le preocupa leer archivos de gran tamaño y quiere romper el proceso.

3

Como toca DannySmurf 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.
Parte del código áspera en el 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 le n docs debe dar con XML correcto y la posibilidad de fusionarlos de nuevo juntos.
Pero de nuevo, depende del archivo xml.

1

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).

0

Parece que está 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 mensajes pareja de blog para que pueda empezar por el camino:

0

No está seguro de qué tipo de procesamiento que está haciendo, pero por muy grande XML , 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.

http://saxdotnet.sourceforge.net/

0

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.

0

Si no es 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.

5

El análisis de documentos XML con DOM no tiene escala.

-script está utilizando 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 el 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() 
0

hice un vídeo de YouTube que muestra how to split XML files con foxe (el editor XML libre de Firstobject) utilizando sólo una pequeña cantidad de memoria independientemente del tamaño de los archivos de entrada y salida.

El uso de memoria para este lector CMarkup XML (analizador pull) y la solución de escritor XML depende del tamaño de los subdocumentos transferidos individualmente del archivo de entrada a los archivos de salida o del tamaño mínimo de bloque 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; 
}
Cuestiones relacionadas