特定のフィールドのみをフィルタリングしたい大規模な(数十万のレコードを含む)XMLファイルがあります。ファイル構成の例:
<A>
<id>123</id>
<B>
<C>value1</C>
<D>value2</D>
....
<E></E>
</B>
<Z></Z>
...
<Y></Y>
<A>
このXMLファイルをフィルタリングし、CフィールドとDフィールドに含まれるIDとデータのみを含めたいです。
どうすればいいですか?
答え1
これxmlstarletこのツールは次のことを行います。
xmlstarlet sel -t -m /A -o ID, -v id -n -o C, -v //C -n -o D, -v //D -n test.xml
ルート要素()-m /A
の下の各Aについて、文字列「ID」(-o ID,
)、idの内容()-v id
、改行()を印刷し、子要素C()、D()、-n
およびその項目についても同様です。ヘッダー。二重スラッシュは、「ノードの下のどこにでも一致」を意味するXPathです。-v //C
-v //D
テストファイルを使用して自分のシステムでテストした結果は、カンマ区切りの出力です。
ID,123
C,value1
D,value2
ヘッダーが必要ない場合は、-o <whatever>
パラメータを省略してください。
ありがとうこの記事説明する。
答え2
この質問に正しく答えるには、理想的にはより良い例が必要です。効果的なxmlは良いスタートです。
また - 希望の出力の例です。たとえば、生成されたXMLで<C>
要素<D>
が終わる場所を指定する必要はありません。彼らすでに子項目 - ルートだけでなく親項目も維持するか、親に戻しますか<B>
? B
C
D
しかし、一般的に言えば、使用と再構築は非常に簡単ですXML
。XML::Twig
perl
たとえば、次のようになります。
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
my @wanted = qw ( C D id );
my %wanted = map { $_ => 1 } @wanted;
sub delete_unwanted_tags {
my ( $twig, $element ) = @_;
my $tag = $element -> tag;
if ( not $wanted{$tag} ) {
$element -> delete;
}
}
my $twig = XML::Twig -> new ( twig_handlers => { _all_ => \&delete_unwanted_tags } );
$twig -> parse ( \*DATA );
$twig -> print;
__DATA__
<A>
<id>123</id>
<B>
<C>value1</C>
<D>value2</D>
<E></E>
</B>
<Z></Z>
<Y></Y>
</A>
「維持」とは言わなかったので、<B>
結果は次のようになります。
<A>
<id>123</id>
</A>
<B>
リストに追加wanted
:
<A>
<id>123</id>
<B>
<C>value1</C>
<D>value2</D>
</B>
</A>
ただし、目的の操作が親を再割り当てし、C
次D
のように入力した場合A
:
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
my @wanted = qw ( id);
my @reparent = qw ( C D );
#turn the above into hashes, so we can do "if $wanted{$tag}"
my %wanted = map { $_ => 1 } @wanted;
my %reparent = map { $_ => 1 } @reparent;
sub delete_unwanted_tags {
my ( $twig, $element ) = @_;
my $tag = $element->tag;
if ( not $wanted{$tag} ) {
$element->delete;
}
if ( $reparent{$tag} ) {
$element->move( 'last_child', $twig->root );
}
}
my $twig = XML::Twig->new(
pretty_print => 'indented_a',
twig_handlers => { _all_ => \&delete_unwanted_tags }
);
$twig->parse( \*DATA );
$twig->print;
__DATA__
<A>
<id>123</id>
<B>
<C>value1</C>
<D>value2</D>
<E></E>
</B>
<Z></Z>
<Y></Y>
</A>
注 - 「木の枝ハンドラ」終わり各要素の値(閉じるタグが見つかったとき)が機能する理由です。処理(および削除)を完了する前に、再帰的に合計を見つけますC
。D
B
これで以下が生成されます。
<A>
<id>123</id>
<C>value1</C>
<D>value2</D>
</A>
__DATA__
上記では、XMLとスキルを説明できるものを\*DATA
使用しました。parse
おそらくparsefile('my_file.xml')
使用する必要がありますparse(\*DATA)
。
答え3
ltXML2ツールキット(エジンバラ大学)のlxgrepを使用してください。
$ lxgrep -w A '(id|C|D)' test.xml
<A>
<id>123</id>
<C>value1</C>
<D>value2</D>
</A>
このタイプのツールの使用は遠く直接するよりも速くて安定しています。
XML FAQ:http://xml.silmaril.ie/