【问题标题】:Split XML based on Tag values根据标签值拆分 XML
【发布时间】:2013-04-16 09:27:22
【问题描述】:

您好,我有一个 XML,我希望根据其中的标签值将其拆分为多个 XML。

例子:-

<HEADER>
<ROOT>
<TAG1>ABC</TAG1> 
<TAG2>78011DAC8</TAG2> 
<TAG3>US78011DAC83</TAG3> 
</ROOT>
<ROOT>
<TAG1>ABC</TAG1> 
<TAG2>78011DAD6</TAG2> 
<TAG3>US78011DAD66</TAG3> 
</ROOT>
<ROOT>
<TAG1>ABC</TAG1> 
<TAG2>B06983611</TAG2> 
<TAG3>GB0009075325</TAG3> 
</ROOT>
<ROOT>
<TAG1>ABC</TAG1> 
<TAG2>B06983629</TAG2> 
<TAG3>GB0009081828</TAG3> 
</ROOT>
<ROOT>
<TAG1>ABC</TAG1> 
<TAG2>BRS038D62</TAG2> 
<TAG3>FR0010050559</TAG3> 
</ROOT>
<ROOT>
<TAG1>ABC</TAG1> 
<TAG2>BRS49ESZ5</TAG2> 
<TAG3>GB00B1Z5HQ14</TAG3> 
</ROOT>
<ROOT>
<TAG1>DEF</TAG1> 
<TAG2>B06983637</TAG2> 
<TAG3>GB0008983024</TAG3> 
</ROOT>
<ROOT>
<TAG1>DEF</TAG1> 
<TAG2>BRS26Y2R4</TAG2> 
<TAG3>GB00B128DH60</TAG3> 
</ROOT>
<ROOT>
<TAG1>DEF</TAG1> 
<TAG2>BRS1JW2X3</TAG2> 
<TAG3>FR0010235176</TAG3> 
</ROOT>
<ROOT>
<TAG1>DEF</TAG1> 
<TAG2>BRS1JW2Y1</TAG2> 
<TAG3>GB00B0CNHZ09</TAG3> 
</ROOT>
<ROOT>
<TAG1>DEF</TAG1> 
<TAG2>BRS3BP9P2</TAG2> 
<TAG3>GB00B1L6W962</TAG3> 
</ROOT>
<ROOT>
<TAG1>DEF</TAG1> 
<TAG2>BRS7FFAV6</TAG2> 
<TAG3>GB00B3D4VD98</TAG3> 
</ROOT> 
<ROOT>
<TAG1>DEF</TAG1> 
<TAG2>B0A07E1X7</TAG2> 
<TAG3>GB0031790826</TAG3> 
</ROOT>
<ROOT>
<TAG1>DEF</TAG1> 
<TAG2>BRS1Z0T57</TAG2> 
<TAG3>GB00B0V3WQ75</TAG3> 
</ROOT>
<ROOT>
<TAG1>XYZ</TAG1> 
<TAG2>BRS9ZDYJ6</TAG2> 
<TAG3>FR0010899765</TAG3> 
</ROOT>
<ROOT>
<TAG1>XYZ</TAG1> 
<TAG2>BRS8ANE14</TAG2> 
<TAG3>DE0001030526</TAG3> 
</ROOT>
<ROOT>
<TAG1>XYZ</TAG1> 
<TAG2>BRS22TXL8</TAG2> 
<TAG3>DE0001030500</TAG3> 
</ROOT>
<ROOT>
<TAG1>XYZ</TAG1> 
<TAG2>BRS5LHPB7</TAG2> 
<TAG3>GB00B24FFM16</TAG3> 
</ROOT>
<ROOT>
<TAG1>XYZ</TAG1> 
<TAG2>B06983223</TAG2> 
<TAG3>GB0008932666</TAG3> 
</ROOT>
</HEADER>

在上面的示例中,我需要检查 TAG1 值,如果它与下一个 TAG1 值匹配,则不应拆分,如果不匹配,则应拆分为新的 XML 文件...

感谢您的帮助!!!

【问题讨论】:

标签: xml perl tags


【解决方案1】:

这是使用 XML::Twig 执行此操作的相对简单的方法。保存在内存中的最大大小是一个完整的子文件,以防这很重要(可以做得更好,在内存中最多保留 1 个ROOT)。

#!/usr/bin/perl

use strict;
use warnings;

use autodie qw( open);

use XML::Twig;

my $in_file = $ARGV[0];

my $out_file= "$in_file.p";
my $i="01";
my $current_tag1='';


my $twig=XML::Twig->new(   
    twig_handlers => { 
       ROOT => sub { my( $t, $root)= @_;
                     $current_tag1||= $root->field( 'TAG1');      # initialize current tag if needed

                     if( $root->field( 'TAG1') ne $current_tag1)  # found a break in the value of TAG1 
                       { 
                         $root->cut;                              # get the new root out of the way
                         $t->print_to_file( $out_file. $i++);     # output the part
                         $t->purge;                               # remove the content of the part
                         $root->paste( first_child => $t->root);  # put the new root back in place

                         $current_tag1=  $root->field( 'TAG1'); 
                       }
                   }
    },
    keep_spaces => 1, # to keep line returns
);

$twig->parsefile($in_file);
$twig->print_to_file( $out_file . $i); # output the last part

【讨论】:

  • 谢谢 mirod .. 这个脚本能够根据 TAG1 值拆分文件,但我想根据一些记录数(比如 3)拆分 XML 文件并检查 TAG1 值是否立即如果匹配则记录,即使记录数为 3,也不要中断。而是仅在未找到相同的 TAG1 值后停止...在我们的示例中,前 5 条记录的 TAG1 值为 ABC,因此第一个 part1 xml 文件应该有 5 条记录(即使我们检查 3 条记录的数量)等等....
  • 文件的拆分是在处理程序的 if 块中完成的。这不会改变。你需要找到合适的条件来触发分裂。我认为,如果您添加一个为每个 ROOT 元素递增的计数器,并在拆分时重置,则正确的条件将是当前的 AND $counter > $MIN_ROOT_IN_FILE。你已经完成了 80% 的路,勇气!
  • 感谢 mirod 的更新。这里的问题是在 if 循环中我无法在达到最大或最小记录值后重置该值...您可以帮助添加此条件以及 TAG1 值检查...非常感谢...
  • 尝试更多。你有所有的元素来做到这一点。
  • 嗨 mirod ...非常需要你的帮助 ...我实际上对 Perl 很陌生,知识很少..我已经包含了一个 $counter ,它为每个 ROOT 递增并包含条件$counter > min_record ..但问题是它没有先检查记录条件,然后再检查实际标签值...请帮助我包括实际检查 min_record 检查的条件,然后再检查 TAG1 值和相应地分裂......
【解决方案2】:

最后我找到了修复.. 下面是检查计数和标签值的代码......

#!/usr/bin/perl

use strict;
use warnings;

use autodie qw( open);

use XML::Twig;

my $in_file = $ARGV[0];

my $out_file= "$in_file.p";
my $i="01";
my $current_tag1='';
my $previous_tag1 = '';
my $nb_root_in_file  =0;
my $MIN_ROOT_IN_FILE = 5;


my $twig=XML::Twig->new(   
twig_handlers => { 
   ROOT => sub { my( $t, $root)= @_;
   $current_tag1||= $root->field( 'TAG1');      # initialize current tag if needed
   $nb_root_in_file++;
   if( $nb_root_in_file > $MIN_ROOT_IN_FILE && $root->field( 'TAG1') ne $current_tag1)  # found a break in the value of TAG1 
                   { 
                     $root->cut;                   # get the new root out of the way
                     $t->print_to_file( $out_file. $i++);     # output the part
                     $t->purge;                       # remove the content of the part
              $root->paste( first_child => $t->root);  # put the new root back in place
                     $current_tag1=  $root->field( 'TAG1'); 
                     $nb_root_in_file =0;
                   }
                    $previous_tag1 = $current_tag1;
               }
 },
keep_spaces => 1, # to keep line returns
 );

 $twig->parsefile($in_file);
  $twig->print_to_file( $out_file . $i); # output the last part

【讨论】:

    【解决方案3】:

    也许你可以用

    来解析它
    use XML::Simple;
    
    my $xml = XMLin($your_xml);
    

    然后像

    if ($xml->{HEADER}->[0]->{ROOT}->{TAG1} == $xml->{HEADER}->[1]->{ROOT}->{TAG1}) { ... }
    

    我其实不知道输出的 xml struc

    【讨论】:

    • 输出应根据 TAG1 值拆分为多个 xml ......因为前 6 条记录的 TAG1 值为 ABC ..这 6 条记录应写入新的 XML 文件名,扩展名为Part1 左右......并且由于接下来的 8 条记录的 TAG1 值不同......这 8 条记录应该写入 xml 文件名 part2 等等......
    猜你喜欢
    • 1970-01-01
    • 2015-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    • 1970-01-01
    • 2018-03-01
    相关资源
    最近更新 更多