Как я могу разбить XML-документ на три части (или, что еще лучше, n частей)?
Я хотел бы использовать знакомый язык - Java, C#, Ruby, PHP, C / C++, хотя примеры на любом языке или псевдокоде более чем приветствуются.
Как лучше всего разбить большой XML-документ на более мелкие разделы, которые по-прежнему являются допустимым XML? Для моих целей мне нужно разделить их примерно на трети или четверти, но для того, чтобы предоставить примеры, было бы хорошо разделить их на n компонентов.
Ответов (10)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 (включая его сохранение. обратно на диск и т. д.).
Если у вас нет полной аллергии на Perl, тогда XML :: Twig поставляется с инструментом под названием xml_split, который может разбивать документ, создавая правильно сформированный раздел XML. Вы можете разделить на уровне дерева, по размеру или по выражению XPath.
Анализ XML-документов с использованием DOM не масштабируется.
Этот Groovy -скрипт использует StAX (Streaming API for XML) для разделения XML-документа между элементами верхнего уровня (которые имеют то же QName, что и первый дочерний элемент корневого документа). Это довольно быстро, обрабатывает произвольные большие документы и очень полезно, когда вы хотите разделить большой пакетный файл на более мелкие части.
Требуется Groovy на Java 6 или StAX API и реализация, такая как 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()
Он прочитал бы весь файл сразу. По моему опыту, однако, если вы просто читаете файл, выполняете некоторую обработку (то есть разбиваете его), а затем продолжаете свою работу, XmlDocument будет проходить цикл создания / чтения / сбора так быстро, что это, вероятно, не имеет значения.
Конечно, это зависит от того, что такое «большой» файл. Если это XML-файл размером 30 МБ (который я бы считал большим для XML-файла), это, вероятно, не будет иметь никакого значения. Если это XML-файл размером 500 МБ, использование XmlDocument станет чрезвычайно проблематичным в системах без значительного объема ОЗУ (в этом случае, однако, я бы сказал, что время ручного выбора файла с помощью XmlReader было бы более значительным. препятствие).
Как отмечает здесь ДэнниСмурф, все дело в структуре 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.
Не уверен, какой тип обработки вы выполняете, но для очень больших XML я всегда был поклонником обработки на основе событий. Может быть, это мой опыт работы с Java, но мне действительно нравится SAX. Вам нужно самостоятельно управлять состоянием, но как только вы это преодолеете, это очень эффективный метод синтаксического анализа XML.
Я собираюсь поддержать вас в этом вопросе. Для очень больших файлов SAX (или любой другой потоковый парсер) будет большим подспорьем в обработке. Используя DOM, вы можете собирать только узлы верхнего уровня, но вам все равно придется анализировать весь документ, чтобы сделать это ... использование потокового парсера и обработки на основе событий позволяет вам «пропускать» узлы, которые вам не интересны; ускоряет обработку.
Я сделал видео на YouTube, показывающее, как разделить файлы XML с помощью foxe (бесплатного редактора XML от Firstobject ), используя лишь небольшой объем памяти, независимо от размера входных и выходных файлов.
Использование памяти для этого решения CMarkup XML для чтения (синтаксический анализатор) и записи XML зависит от размера вложенных документов, которые индивидуально передаются из входного файла в выходные файлы, или от минимального размера блока 16 КБ.
расколоть() { CMarkup xmlInput, xmlOutput; xmlInput.Open («50 МБ.xml», MDF_READFILE); int nObjectCount = 0, nFileCount = 0; while (xmlInput.FindElem ("// ДЕЙСТВИЕ")) { если (nObjectCount == 0) { ++ nFileCount; xmlOutput.Open («кусок» + nFileCount + «.xml», MDF_WRITEFILE); xmlOutput.AddElem («корень»); xmlOutput.IntoElem (); } xmlOutput.AddSubDoc (xmlInput.GetSubDoc ()); ++ nObjectCount; если (nObjectCount == 5) { xmlOutput.Close (); nObjectCount = 0; } } если (nObjectCount) xmlOutput.Close (); xmlInput.Close (); return nFileCount; }