Come posso dividere un documento XML in terzi (o, ancora meglio, di n pezzi)?

StackOverflow https://stackoverflow.com/questions/7846

  •  08-06-2019
  •  | 
  •  

Domanda

Vorrei utilizzare un linguaggio che ho una conoscenza di con - Java, C#, Ruby, PHP, C/C++, anche se gli esempi in qualsiasi lingua o pseudocodice sono più che benvenuti.

Qual è il miglior modo di dividere un documento XML di grandi dimensioni in piccole sezioni che sono ancora XML valido?Per i miei scopi, ho bisogno di dividere in circa terzi o quarti, ma per il bene di fornire esempi, la loro suddivisione in n componenti sarebbe buono.

È stato utile?

Soluzione

Beh, certo si può sempre estrarre gli elementi di livello superiore (se questo è il livello di dettaglio che si desidera è fino a voi).In C#, devi utilizzare la classe XmlDocument.Per esempio, se il file XML sembrava qualcosa di simile a questo:

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

poi devi usare questo codice per estrarre tutti i Pezzi:

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 volta che hai i nodi, si può fare qualcosa con loro nel codice, oppure è possibile trasferire l'intero testo del nodo XML del documento e agire come se si trattasse di un indipendente pezzo di XML (compreso il salvataggio su disco, ecc).

Altri suggerimenti

Il Parsing di documenti XML con DOM non scala.

Questo Groovy-script utilizza StAX (API for XML) per dividere un documento XML tra gli elementi di primo livello (che condivide lo stesso QName come il primo figlio della radice del documento).È abbastanza veloce, maniglie arbitrarie di documenti di grandi dimensioni ed è molto utile quando si desidera dividere un grande file in pezzi più piccoli.

Richiede Groovy su Java 6 o StAX API e di attuazione, ad esempio Woodstox nel 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()

Come DannySmurf tocca qui, è tutto circa la struttura del documento xml.
Se hai solo due enormi "livello superiore" tag sarà estremamente difficile essere in grado di dividere in un modo che rende possibile sia il merge di nuovo insieme e leggere, pezzo per pezzo, come un xml valido.

Dato un documento con un sacco di pezzi separati, come quelli DannySmurfs esempio, dovrebbe essere abbastanza facile.
Un po ' ruvido in Pseudo codice 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);
}

Questo dovrebbe darvi n docs con xml corretto e la possibilità di unire di nuovo insieme.
Ma, ripeto, dipende dal file xml.

Questo è più di un commento di una risposta, ma non sarebbe:

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

Leggere l'intero file in una sola volta?Solo pensato che dovrei alzare il punto, poiché il look di Thomas domanda, egli è preoccupato per la lettura di file di grandi dimensioni e vuole rompere il processo..

Sarebbe leggere l'intero file in una sola volta.Nella mia esperienza, però, se si sta semplicemente leggendo il file, fare qualche trattamento (cioè, rompendo in su) e poi continuare con il vostro lavoro, XmlDocument sta per andare attraverso di essa per creare, leggere, raccogliere ciclo così rapidamente che, probabilmente, non importa.

Naturalmente, questo dipende da quello che un "grande" file.Se sono 30 MB di file XML (che vorrei prendere in considerazione di grandi dimensioni per un file XML), probabilmente non farà alcuna differenza.Se è un 500 MB di file XML, utilizzando XmlDocument diventa estremamente problematico su sistemi privi di una significativa quantità di RAM (in questo caso, tuttavia, direi che il tempo per la raccolta manuale tramite il file con un XmlReader sarebbe il più significativo impedimento).

Non sono sicuro di che tipo di elaborazione che si sta facendo, ma per molto XML di grandi dimensioni, sono sempre stato un fan di eventi a base di elaborazione.Forse è la mia versione di Java sfondo, ma mi piace davvero SAX.Hai bisogno di fare il vostro proprio la gestione dello stato, ma una volta passato, è un modo molto efficiente di parsing di XML.

http://saxdotnet.sourceforge.net/

Ho intenzione di andare con youphoric su questo.Per file di dimensioni molto grandi SAX (o qualsiasi altro streaming parser) sarà un grande aiuto nel trattamento.Utilizzando DOM è possibile raccogliere solo nodi di livello superiore, ma è ancora necessario per analizzare l'intero documento di farlo...utilizzando streaming di un parser basati su eventi e di elaborazione consente di "saltare" i nodi che non ti interessano;rende il trattamento più veloce.

Se non siete allergici a Perl, quindi XML::Twig viene fornito con uno strumento denominato xml_split che può dividere un documento, producendo ben formato XML sezione.È possibile dividere un livello dell'albero, dalla dimensione o a un'espressione XPath.

Sembra che si sta lavorando con C# e .NET 3.5.Mi sono imbattuto in alcuni post che suggeriscono l'utilizzo di un tipo di rendimento dell'algoritmo su un file stream con un XmlReader.

Ecco un paio di post di blog per iniziare il percorso:

Ho fatto un video di YouTube che mostrano come dividere file XML con foxe (la connessione XML editor Firstobject) utilizzando solo una piccola quantità di memoria, indipendentemente dalla dimensione dell'input e di output dei file.

L'utilizzo della memoria per questo CMarkup XML reader (pull parser) e XML writer soluzione dipende dalla dimensione dei documenti che sono individualmente trasferiti dal file di input per il file di output, o la minima dimensione del blocco di 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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top