Как я могу разделить XML-документ на три части (или, что еще лучше, на n частей)?

Я хотел бы использовать знакомый мне язык - Java, C #, Ruby, PHP, C / C ++, хотя примеры на любом языке или псевдокоде приветствуются.

Каков наилучший способ разбить большой XML-документ на более мелкие разделы, которые все еще являются действительным XML? Для моих целей мне нужно разделить их примерно на треть или четверть, но для того, чтобы привести примеры, было бы полезно разделить их на n компонентов.

7 xml
11.08.2008 15:04:21
10 ОТВЕТОВ
РЕШЕНИЕ

Конечно, вы всегда можете извлечь элементы верхнего уровня (независимо от того, хотите ли вы, чтобы детализация была на ваше усмотрение). В C # вы бы использовали класс XmlDocument. Например, если ваш XML-файл выглядел примерно так:

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

тогда вы будете использовать такой код для извлечения всех частей:

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
}

Получив узлы, вы можете что-то сделать с ними в своем коде или перенести весь текст узла в его собственный XML-документ и действовать так, как если бы он был независимым фрагментом XML (включая его сохранение). обратно на диск и т. д.).

3
11.08.2008 15:13:14

Это скорее комментарий, чем ответ, но не будет:

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

Читать весь файл сразу? Просто подумал, что мне следует поднять этот вопрос, поскольку, судя по вопросу Томаса, он обеспокоен чтением больших файлов и хочет прервать процесс ..

1
11.08.2008 15:28:08

Как DannySmurf затрагивает здесь, это все о структуре документа XML.
Если вы используете только два огромных тега «верхнего уровня», вам будет крайне сложно разделить его таким образом, чтобы можно было объединить его вместе и считывать его по частям как действительный xml.

Учитывая документ с большим количеством отдельных частей, таких как в примере DannySmurfs, это должно быть довольно легко.
Немного грубого кода в псевдо 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);
}

Это должно дать вам n документов с правильным XML и возможность объединить их вместе.
Но опять же, это зависит от XML-файла.

3
11.08.2008 15:31:11

Это прочитало бы весь файл сразу. Однако, по моему опыту, если вы просто читаете файл, выполняете некоторую обработку (то есть разбиваете его), а затем продолжаете свою работу, XmlDocument собирается пройти цикл создания / чтения / сбора так быстро, что это вероятно не будет иметь значения.

Конечно, это зависит от того, что такое «большой» файл. Если это XML-файл размером 30 МБ (который я считаю большим для XML-файла), это, вероятно, не будет иметь никакого значения. Если это XML-файл объемом 500 МБ, использование XmlDocument станет чрезвычайно проблематичным в системах без значительного объема ОЗУ (однако в этом случае я бы сказал, что время ручного выбора файла с помощью XmlReader будет более значительным препятствие).

1
16.01.2010 22:04:10

Похоже, вы работаете с C # и .NET 3.5. Я сталкивался с некоторыми сообщениями, которые предлагают использовать алгоритм типа yield в файловом потоке с XmlReader.

Вот пара сообщений в блоге, которые помогут вам начать путь:

0
16.01.2010 22:03:21

Не уверен, какой тип обработки вы делаете, но для очень большого XML я всегда был поклонником обработки на основе событий. Может быть, это мой опыт Java, но мне действительно нравится SAX. Вам нужно заниматься собственным управлением состоянием, но как только вы это преодолеете, это очень эффективный метод анализа XML.

http://saxdotnet.sourceforge.net/

0
16.09.2008 13:24:18

Я собираюсь пойти с юфорикой на этот. Для очень больших файлов SAX (или любой другой потоковый парсер) будет отличным помощником в обработке. Используя DOM, вы можете собирать только узлы верхнего уровня, но вам все равно придется анализировать весь документ, чтобы сделать это ... используя потоковый анализатор и обработку на основе событий, позволяет "пропустить" узлы, которые вам не интересны; делает обработку быстрее.

0
16.09.2008 13:31:30

Если у вас нет полной аллергии на Perl, тогда XML :: Twig поставляется с инструментом с именем xml_split, который может разбить документ, создавая правильно сформированный раздел XML. Вы можете разделить по уровню дерева, по размеру или по выражению XPath.

0
16.09.2008 15:40:43

Разбор XML-документов с использованием DOM не масштабируется.

Этот Groovy- скрипт использует StAX (Streaming API for XML) для разделения XML-документа между элементами верхнего уровня (который имеет то же QName, что и первый дочерний элемент корневого документа). Это довольно быстро, обрабатывает произвольные большие документы и очень полезно, когда вы хотите разделить большой пакетный файл на более мелкие части.

Требуется Groovy на Java 6 или API StAX и такая реализация, как Woodstox в 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()
5
11.04.2011 15:56:33

Я снял на YouTube видео, показывающее, как разделять XML-файлы с помощью foxe (бесплатный XML-редактор от Firstobject ), используя только небольшой объем памяти независимо от размера входных и выходных файлов.

Использование памяти для этого CMarkup XML reader (pull parser) и решения для записи XML зависит от размера вложенных документов, которые индивидуально переносятся из входного файла в выходные файлы, или от минимального размера блока 16 КБ.

Трещина()
{
  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
16.01.2010 22:12:38