Cum pot împărți un document XML în treimi (sau, chiar mai bine, n bucăți)?

Aș dori să folosesc o limbă pe care o cunosc - Java, C#, Ruby, PHP, C/C ++, deși exemplele în orice limbă sau pseudocod sunt mai mult decât binevenite.

Care este cel mai bun mod de a împărți un document xml mare în secțiuni mai mici, care sunt încă valide XML? În scopurile mele, trebuie să le împărțim în aproximativ treimi sau patru, dar pentru a oferi exemple, divizarea lor în n componente ar fi bună.

0
fr hi bn

8 răspunsuri

Acesta este mai mult un comentariu decât un răspuns, dar nu ar:

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

Citiți întregul fișier deodată? M-am gândit că ar trebui să ridic punctul de vedere, deoarece de la aspectul întrebării lui Thomas, este preocupat de citirea fișierelor mari și vrea să spargă procesul în jos.

0
adăugat

As DannySmurf touches on here, it is all about the structure of the xml document.
If you only two huge "top level" tags, it will be extremely hard to be able to split it in a way that makes it possible to both merge it back together and read it piece by piece as valid xml.

Given a document with a lot of seperate pieces like the ones in DannySmurfs example, it should be fairly easy.
Some rough code in Pseudo C# :

int nrOfPieces = 5;
XmlDocument xmlOriginal = some input parameter..

// construct the list we need, and fill it with XmlDocuments..
var xmlList = new List();
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);
}

This should give you n docs with correct xml and the possibility to merge them back together.
But again, it depends on the xml file.

0
adăugat

Dacă nu sunteți complet alergic la Perl, atunci XML: : Twig vine cu un instrument numit xml_split care poate diviza un document, producând o secțiune xml bine formată. Puteți să vă împărțiți pe un nivel al copacului, după dimensiune sau pe o expresie XPath.

0
adăugat

Desigur, puteți extrage elementele de nivel superior (dacă aceasta este granularitatea pe care o doriți este de până la dvs.). În C#, ați folosi clasa XmlDocument. De exemplu, dacă fișierul dvs. xml arăta astfel:


  
     Some text
  
  
     Some other text
  

atunci veți folosi codul ca acesta pentru a extrage toate piesele:

XmlDocument doc = new XmlDocument();
doc.Load("xml file>");
XmlNodeList nl = doc.GetElementsByTagName("Piece");
foreach (XmlNode n in nl)
{
   //Do something with each Piece node
}

Odată ce ați primit nodurile, puteți face ceva cu ele în codul dvs. sau puteți transfera întregul text al nodului în propriul document xml și să acționați asupra acestuia ca și cum ar fi o piesă independentă de xml (inclusiv salvarea acestuia înapoi la disc etc.).

0
adăugat

Va citi întregul dosar deodată. Din experiența mea însă, dacă citiți doar fișierul, faceți o prelucrare (de exemplu, rupeți-l) și apoi continuați cu munca dvs., XmlDocument va trece prin ciclul de creare/citire/colectare atât de repede încât probabil că nu contează.

Desigur, asta depinde de ceea ce este un fișier "mare". Dacă este vorba despre un fișier xml de 30 MB (pe care l-aș considera mare pentru un fișier XML), probabil că nu va face nimic. Dacă este vorba despre un fișier xml de 500 MB, utilizarea lui XmlDocument va deveni extrem de problematică în sistemele fără o cantitate semnificativă de RAM (în acest caz însă aș susține că timpul pentru selectarea manuală a fișierului cu un XmlReader ar fi mai semnificativ impediment).

0
adăugat

Se pare că lucrați cu C# și .NET 3.5. Am întâlnit câteva mesaje care sugerează utilizarea unui tip de randament al algoritmului pe un flux de fișiere cu un XmlReader.

Iată câteva postări pe blog pentru a vă face să începeți calea:

0
adăugat

Parsarea documentelor xml folosind DOM nu scară.

Acest script Groovy folosește StAX (Streaming API for XML) pentru a împărți un document xml între cel mai înalt nivel (care împărtășește același nume QName cu primul copil al documentului rădăcină). Este destul de rapid, se ocupă de documente mari arbitrare și este foarte util atunci când doriți să împărțiți un fișier lot mare în bucăți mai mici.

Necesită Groovy pe Java 6 sau un API StAX și implementare, cum ar fi Woodstox în 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
adăugat

Am făcut un videoclip YouTube care afișează modul de împărțire a fișierelor xml cu foxe (editorul xml gratuit de la Firstobject ) folosind doar o cantitate mică de memorie indiferent de dimensiunea fișierelor de intrare și de ieșire.

Utilizarea memoriei pentru acest cititor xml CMarkup xml și scriitor xml depinde de dimensiunea subdocumentelor transferate individual de la fișierul de intrare la fișierele de ieșire sau de dimensiunea minimă de bloc 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;
}
0
adăugat