我试图将一个大的xml文件拆分成多个文件,并在AWK脚本中使用了以下代码。
/<fileItem>/ {
rfile="fileItem" count ".xml"
print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > rfile
print $0 > rfile
getline
while ($0 !~ "<\/fileItem>" ) {
print > rfile
getline
}
print $0 > rfile
close(rfile)
count++
}
上面的代码生成一个xml文件列表,其名称为&#34; fileItem_1&#34;,&#34; fileItem_2&#34;,&#34; fileItem3&#34;等。
但是,我希望文件名类似&#34; item_XXXXX&#34;其中XXXXX是XML中的一个节点 - 如下所示
<fileItem>
<id>12345</id>
<name>XXXXX</name>
</fileItem>
所以,基本上我想要&#34; id&#34;节点是文件名。 有人可以帮我这个吗?
答案 0 :(得分:2)
我不会使用getline
。 (我甚至在AWK书中读过,不建议使用它。)我认为,使用全局变量进行状态更简单。 (具有全局变量的表达式也可以用于模式中。)
脚本可能如下所示:
test-split-xml.awk
:
/<fileItem>/ {
collect = 1 ; buffer = "" ; file = "fileItem_"count".xml"
++count
}
collect > 0 {
if (buffer != "") buffer = buffer"\n"
buffer = buffer $0
}
collect > 0 && /<name>.+<\/name>/ {
# cut "...<name>"
i = index($0, "<name>") ; file = substr($0, i + 6)
# cut "</name>..."
i = index(file, "</name>") ; file = substr(file, 1, i - 1)
file = file".xml"
}
/<\/fileItem>/ {
collect = 0;
print file
print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" >file
print buffer >file
}
我为一个小测试准备了一些样本数据:
test-split-xml.xml
:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<top>
<some>
<fileItem>
<id>1</id>
<name>X1</name>
</fileItem>
</some>
<fileItem>
<id>2</id>
<name>X2</name>
</fileItem>
<fileItem>
<id>2</id>
<!--name>X2</name-->
</fileItem>
<any> other input </any>
</top>
...并得到以下输出:
$ awk -f test-split-xml.awk test-split-xml.xml
X1.xml
X2.xml
fileItem_2.xml
$ more X1.xml
<?xml version="1.0" encoding="UTF-8"?>
<fileItem>
<id>1</id>
<name>X1</name>
</fileItem>
$ more X2.xml
<?xml version="1.0" encoding="UTF-8"?>
<fileItem>
<id>2</id>
<name>X2</name>
</fileItem>
$ more fileItem_2.xml
<?xml version="1.0" encoding="UTF-8"?>
<fileItem>
<id>2</id>
<!--name>X2</name-->
</fileItem>
$
tripleee的评论是合理的。因此,此类处理应限于个人使用,因为XML文件的不同(和合法)格式化可能会导致此脚本处理出错。
正如您将注意到的,整个脚本中没有next
。这是故意的。
答案 1 :(得分:2)
首先 - 你需要一个解析器。
XML是一种上下文数据格式。正则表达式不是。所以你可以永远使正则表达式基本处理系统实际上正常工作。
但解析器确实存在,并且它们很容易使用。我可以通过更好的数据输入为您提供更好的示例。但我会使用XML::Twig
和perl
来执行此操作:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
#subroutine to extract and process the item
sub save_item {
my ( $twig, $item ) = @_;
#retrieve the id
my $id = $item -> first_child_text('id');
print "Got ID of $id\n";
#create a new XML document for output.
my $new_xml = XML::Twig -> new;
$new_xml -> set_root (XML::Twig::Elt -> new ( 'root' ));
#cut and paste the item from the 'old' doc into the 'new'
#note - "cut" applies to in memory,
#not the 'on disk' copy.
$item -> cut;
$item -> paste ( $new_xml -> root );
#set XML params (not strictly needed but good style)
$new_xml -> set_encoding ('utf-8');
$new_xml -> set_xml_version ('1.0');
#set output formatting
$new_xml -> set_pretty_print('indented_a');
print "Generated new XML:\n";
$new_xml -> print;
#open a file for output
open ( my $output, '>', "item_$id.xml" ) or warn $!;
print {$output} $new_xml->sprint;
close ( $output );
}
#create a parser.
my $twig = XML::Twig -> new ( twig_handlers => { 'fileItem' => \&save_item } );
#run this parser on the __DATA__ filehandle below.
#you probably want parsefile('some_file.xml') instead.
$twig -> parse ( \*DATA );
__DATA__
<xml>
<fileItem>
<id>12345</id>
<name>XXXXX</name>
</fileItem>
</xml>
XML::Twig
来xml_split
可能适合您的需要
答案 2 :(得分:1)
如果您的XML确实形成并且一致,那么您只需要:
awk -F'[<>]' '
/<fileItem>/ { header="<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ORS $0; next }
/<id> { close(out); out="item_" $3; $0=header ORS $0 }
{ print > out }
' file
上述情况当然未经测试,因为您没有为我们提供样本输入/输出来测试可能的解决方案。