大きなXMLファイルを整合性を保ったまま自動分割する方法


batやvbsなど、プログラムを書いてくれる方を探しています。
謝礼は100~500pt、完全解答をお願いします。

たとえば、電話帳を記載したxmlファイルが数種類あります。このファイルを別のプログラムで処理するには重すぎるとします。
サイズだけを基準にぶった切ると処理をするときにxmlの整合性が崩れるので処理ができないという問題が出ます。そこで、整合性を維持したままxmlファイルを分割したいです。batなどのファイルで。

条件
1. 毎回処理する対象のXMLの形式はおおまかに同じ
2. XML は、次のようになっている。

addressbooktokyo.xmlの中身
<xml version="1.0" encoding="utf-8"?>
<任意の一行、定型句>
<header>
<各種ヘッダー情報、たとえば地域などファイルによって微妙に違う>
</header>
<body>
<person>
<name>山田さん</name>
<phone>0123456789</phone>
</person>
膨大な繰り返し・・・
</body>
</xml>

補足に手順イメージを記載しました。

回答の条件
  • URL必須
  • 1人1回まで
  • 登録:
  • 終了:2012/12/13 13:57:37
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。
id:Nigitama

手順イメージ

1. ファイルの初回読み込み時に<xml宣言>プラス<header>から</header>を読み込んで一時的にどこかにキープする(これがヘッダ部分)。

2. <body>内を読み込みながら、output1.xmlファイルに各行を書き出す。

3. 繰り返しが1000行を超えて「かつ」</person>の行を読み込んだときに、</body></xml>を付け足してそのファイルは終了、が、繰り返しは継続

4. 繰り返しを継続するが、出力先はoutput2.xmlにインクリメントし、初回のみ、手順1のヘッダ部分を付け加えて、以下bodyを繰り返す

という流れにできないか、と考えています。

ファイル末尾に至るときにどう処理するかはちょっとした工夫が要るかもしれません。

ベストアンサー

id:Mook No.1

回答回数1314ベストアンサー獲得回数393

ポイント500pt

FileSystemObject でサポートしているのは S-JIS か unicode なので、
ちょっと処理が複雑なのと、処理が遅いかもしれませんが ADODB.stream で
UTF-8 として処理しています。

また、できればきちんと XML として構文処理したほうがよいと思いますが、
例示されたサンプルは MSXML2.DOMDocument で読み込めなかったので、
文字列処理としています。

Option Explicit

'//-----------------------------------
    Const FILE_PATH = "D:\Data\Data.xml"  '// 処理ファイル名
    Const DIV_SIZE = 1000                 '// 1ファイルの分割行数

'//-----------------------------------
    Dim inXML
    Set inXML     = CreateObject("ADODB.Stream")
    inXML.Type    = 2  '// 1:バイナリデータ 2:テキストデータ
    inXML.Charset = "UTF-8"
    inXML.Open
    inXML.LoadFromFile FILE_PATH

'// header(body まで) 読込
'//-----------------------------------
    Dim headerCount
    Dim headerPart
    Dim readOneLine 
    Do While inXML.EOS = False
        readOneLine = inXML.ReadText(-2)
        headerPart= headerPart & readOneLine & vbNewLine
        headerCount = headerCount + 1
        If InStr( UCase( readOneLine ), "<BODY>" ) > 0 Then Exit Do
    Loop

'//-----------------------------------
    Dim outXML
    Set outXML     = CreateObject("ADODB.Stream")
    outXML.Type    = 2  '// 1:バイナリデータ 2:テキストデータ
    outXML.Charset = "UTF-8"

'// person データ読込
'//-----------------------------------
    Dim divFileCount 
    Dim fileCount
    Dim dstXML
    Dim exportFile
    exportFile = ""
    Dim outContents
    Do While inXML.EOS = False
'// 初期化処理
        If exportFile = "" Then
            fileCount = fileCount + 1
            exportFile = "outFile" & fileCount & ".xml"
            outContents = HeaderPart
            divFileCount = headerCount
        End If

        readOneLine = inXML.ReadText(-2)
        outContents = outContents & readOneLine & vbNewLine
        divFileCount  = divFileCount + 1

'// ファイル出力
        If divFileCount > DIV_SIZE Then
            If InStr( UCase( readOneLine ), "</PERSON>" ) > 0 Then
                outContents = outContents & "</body>" & vbNewLine
                outContents = outContents & "</xml>" & vbNewLine
                outXML.Open
                outXML.WriteText outContents, 1
                outXML.SaveToFile exportFile, 2
                outXML.Close
                exportFile = ""
            End If
        End If
    Loop

'// 最後のファイル出力
    If divFileCount <> headerCount Then
        outXML.Open
        outXML.WriteText outContents, 1
        outXML.SaveToFile exportFile, 2
        outXML.Close
    End If
    inXML.Close

http://trwtnb.blogspot.jp/2009/10/vbscriptutf-8.html
http://www.atmarkit.co.jp/fxml/rensai/msxml01/msxml03.html

他9件のコメントを見る
id:Mook

上記のコメントで書いた UNICODE にすれば・・・、という話は単にデータの文字コードを変えるだけでなく、処理を FSO を使うように変更すればという意味で書きました。
ただそれでも2.3GBというファイルを処理するというのは、想像していませんでしたが。

この規模のファイル処理を頻繁にするのであれば、スクリプト処理ではちょっと限界がありそうです。

データの運用フロー(入力から出力まで)が不明ですが、その規模のファイル(データ)を処理するのであれば、XML ではなくODBS を使いたい気がしました。

2012/12/13 11:57:49
id:Nigitama

600GBのファイルはなんとか処理できているのが確認できました。
さすがにこの規模のファイルを扱うことは多くないので、許容範囲かと思います。現状、2.3GBのファイルは機械的に分割して、手動でヘッダとフッタをつけて処理しました。

はてなで別の質問をするかもしれませんが、最初に機械的な分割をして、連番の前と後ろのファイルを参照しながらxmlの整合性をとっていく方法が処理スピードが早いかもしれません。

今回の質問はこれにて終了しようと思います。ぶっちぎりのベストアンサーですありがとうございました。

2012/12/13 13:57:21

その他の回答0件)

id:Mook No.1

回答回数1314ベストアンサー獲得回数393ここでベストアンサー

ポイント500pt

FileSystemObject でサポートしているのは S-JIS か unicode なので、
ちょっと処理が複雑なのと、処理が遅いかもしれませんが ADODB.stream で
UTF-8 として処理しています。

また、できればきちんと XML として構文処理したほうがよいと思いますが、
例示されたサンプルは MSXML2.DOMDocument で読み込めなかったので、
文字列処理としています。

Option Explicit

'//-----------------------------------
    Const FILE_PATH = "D:\Data\Data.xml"  '// 処理ファイル名
    Const DIV_SIZE = 1000                 '// 1ファイルの分割行数

'//-----------------------------------
    Dim inXML
    Set inXML     = CreateObject("ADODB.Stream")
    inXML.Type    = 2  '// 1:バイナリデータ 2:テキストデータ
    inXML.Charset = "UTF-8"
    inXML.Open
    inXML.LoadFromFile FILE_PATH

'// header(body まで) 読込
'//-----------------------------------
    Dim headerCount
    Dim headerPart
    Dim readOneLine 
    Do While inXML.EOS = False
        readOneLine = inXML.ReadText(-2)
        headerPart= headerPart & readOneLine & vbNewLine
        headerCount = headerCount + 1
        If InStr( UCase( readOneLine ), "<BODY>" ) > 0 Then Exit Do
    Loop

'//-----------------------------------
    Dim outXML
    Set outXML     = CreateObject("ADODB.Stream")
    outXML.Type    = 2  '// 1:バイナリデータ 2:テキストデータ
    outXML.Charset = "UTF-8"

'// person データ読込
'//-----------------------------------
    Dim divFileCount 
    Dim fileCount
    Dim dstXML
    Dim exportFile
    exportFile = ""
    Dim outContents
    Do While inXML.EOS = False
'// 初期化処理
        If exportFile = "" Then
            fileCount = fileCount + 1
            exportFile = "outFile" & fileCount & ".xml"
            outContents = HeaderPart
            divFileCount = headerCount
        End If

        readOneLine = inXML.ReadText(-2)
        outContents = outContents & readOneLine & vbNewLine
        divFileCount  = divFileCount + 1

'// ファイル出力
        If divFileCount > DIV_SIZE Then
            If InStr( UCase( readOneLine ), "</PERSON>" ) > 0 Then
                outContents = outContents & "</body>" & vbNewLine
                outContents = outContents & "</xml>" & vbNewLine
                outXML.Open
                outXML.WriteText outContents, 1
                outXML.SaveToFile exportFile, 2
                outXML.Close
                exportFile = ""
            End If
        End If
    Loop

'// 最後のファイル出力
    If divFileCount <> headerCount Then
        outXML.Open
        outXML.WriteText outContents, 1
        outXML.SaveToFile exportFile, 2
        outXML.Close
    End If
    inXML.Close

http://trwtnb.blogspot.jp/2009/10/vbscriptutf-8.html
http://www.atmarkit.co.jp/fxml/rensai/msxml01/msxml03.html

他9件のコメントを見る
id:Mook

上記のコメントで書いた UNICODE にすれば・・・、という話は単にデータの文字コードを変えるだけでなく、処理を FSO を使うように変更すればという意味で書きました。
ただそれでも2.3GBというファイルを処理するというのは、想像していませんでしたが。

この規模のファイル処理を頻繁にするのであれば、スクリプト処理ではちょっと限界がありそうです。

データの運用フロー(入力から出力まで)が不明ですが、その規模のファイル(データ)を処理するのであれば、XML ではなくODBS を使いたい気がしました。

2012/12/13 11:57:49
id:Nigitama

600GBのファイルはなんとか処理できているのが確認できました。
さすがにこの規模のファイルを扱うことは多くないので、許容範囲かと思います。現状、2.3GBのファイルは機械的に分割して、手動でヘッダとフッタをつけて処理しました。

はてなで別の質問をするかもしれませんが、最初に機械的な分割をして、連番の前と後ろのファイルを参照しながらxmlの整合性をとっていく方法が処理スピードが早いかもしれません。

今回の質問はこれにて終了しようと思います。ぶっちぎりのベストアンサーですありがとうございました。

2012/12/13 13:57:21
  • id:SweetSmile1978
    SweetSmile1978 2012/12/11 15:00:00
    言語は bat か vbs 限定ですか?
    個人的には C# でやりたいんですが。
  • id:Nigitama
    言語は特に限定していませんが、特別なソフトをインストールせずにできる方法が望ましいです。

    C#についてはわかりませんが、無料で単一のソフトなどをインストールするだけで簡単にできるのであればそれでも構いません。有料のソフトや、設定に手間がかかる場合は、申し訳ありませんが、回答はお控えください。
  • id:Nigitama
    別の方法で対処するため、質問をし直しました。
    http://q.hatena.ne.jp/1355386180

    分割されたXMLファイルの前後を調節して、整合性をとるvbsを作成してくれる方、お願いします。

この質問への反応(ブックマークコメント)

トラックバック

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません