XML ドキュメントを 3 つ (または、さらに良いのは n 個) に分割するにはどうすればよいでしょうか?

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

  •  08-06-2019
  •  | 
  •  

質問

Java、C#、Ruby、PHP、C/C++ など、使い慣れた言語を使用したいと考えていますが、任意の言語や疑似コードの例は大歓迎です。

大きな XML ドキュメントを有効な XML のままの小さなセクションに分割する最善の方法は何ですか?今回の目的では、これらをおよそ 3 つまたは 4 つに分割する必要がありますが、例を提供するためには、n 個のコンポーネントに分割するのが適切です。

役に立ちましたか?

解決

もちろん、いつでも最上位の要素を抽出できます (これが必要な粒度であるかどうかはあなた次第です)。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 部分であるかのように操作したりできます (保存も含む)。ディスクに戻すなど)。

他のヒント

DOM を使用した XML ドキュメントの解析は拡張できません。

これ グルーヴィー-script は StAX (Streaming API for XML) を使用して、XML ドキュメントを最上位要素 (ルート ドキュメントの最初の子と同じ QName を共有する) 間で分割します。これは非常に高速で、任意の大きなドキュメントを処理できるため、大きなバッチ ファイルを小さな部分に分割する場合に非常に便利です。

Java 6 上の Groovy または StAX API と次のような実装が必要です。 ウッドストックス クラスパス内

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

DannySmurf がここで触れているように、すべては XML ドキュメントの構造に関するものです。
巨大な「トップレベル」タグが 2 つだけの場合、タグを再度マージして有効な 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);
}

これにより、正しい XML を含む n 個のドキュメントが得られ、それらをマージして戻すことができるようになります。
ただし、繰り返しになりますが、それは XML ファイルに依存します。

これは回答というよりコメントですが、そうではありません。

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

ファイル全体を一度に読み取りますか?Thomas の質問を見る限り、彼は大きなファイルの読み取りを懸念しており、プロセスを細分化したいと考えているため、この点を指摘する必要があると思いました。

ファイル全体を一度に読み取ります。ただし、私の経験では、単にファイルを読み取り、何らかの処理 (つまり、ファイルの分割) を行ってから作業を続行している場合、XmlDocument は作成、読み取り、収集のサイクルを非常に迅速に実行します。おそらく関係ないでしょう。

もちろん、それは「大きな」ファイルが何であるかによって異なります。それが 30 MB の XML ファイル (XML ファイルとしては大きいと思います) の場合は、おそらく何の違いもありません。500 MB の XML ファイルの場合、大量の RAM を持たないシステムでは XmlDocument の使用が非常に問題になります (ただし、その場合、XmlReader を使用してファイルを手動で選択する時間の方が重要になると思います)障害)。

どのような種類の処理を行っているのかはわかりませんが、非常に大規模な XML の場合、私は常にイベントベースの処理のファンです。私の Java のバックグラウンドのせいかもしれませんが、私は SAX が大好きです。独自の状態管理を行う必要がありますが、それを乗り越えれば、XML を解析する非常に効率的な方法になります。

http://saxdotnet.sourceforge.net/

これについては youphoric で行きます。非常に大きなファイルの場合、SAX (またはその他のストリーミング パーサー) は処理に非常に役立ちます。DOM を使用すると、トップレベルのノードだけを収集できますが、そのためにはドキュメント全体を解析する必要があります。ストリーミング パーサーとイベントベースの処理を使用すると、興味のないノードを「スキップ」できます。処理が速くなります。

Perl に対して完全なアレルギーがない場合は、 XML::Twig という名前のツールが付属しています xml_split ドキュメントを分割して、整形式の XML セクションを生成することができます。ツリーのレベル、サイズ、または XPath 式で分割できます。

C# と .NET 3.5 を使用しているようです。XmlReader を使用したファイル ストリームに対して、yield タイプのアルゴリズムを使用することを提案する投稿をいくつか見つけました。

この道を歩み始めるためのいくつかのブログ投稿を次に示します。

YouTubeの動画を見せてみました XMLファイルを分割する方法キツネ (無料の XML エディター 最初のオブジェクト) 入力ファイルと出力ファイルのサイズに関係なく、少量のメモリのみを使用します。

この CMarkup XML リーダー (プル パーサー) および XML ライター ソリューションのメモリ使用量は、入力ファイルから出力ファイルに個別に転送されるサブドキュメントのサイズ、または 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;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top