gpt4 book ai didi

xml - 使用 xml_split 根据 Perl 正则表达式或 XPath 表达式拆分 XML 文件

转载 作者:行者123 更新时间:2023-12-02 03:50:47 24 4
gpt4 key购买 nike

我有一个巨大的 XML 文件,我想根据产品类型属性将其拆分为多个 block 。

我不知道如何使用 XSLT。我发现xml_split但不知道如何将它与正则表达式或 XPath 一起使用来根据类型属性分割文档

<?xml version="1.0"?>
<!DOCTYPE catalog SYSTEM "catalog.dtd">
<catalog>
<product type="cloths" product_image="cardigan.jpg">
<catalog_item gender="Men's">
<item_number>QWZ5671</item_number>
<price>39.95</price>
<size description="Medium">
<color_swatch image="red_cardigan.jpg">Red</color_swatch>
<color_swatch image="burgundy_cardigan.jpg">Burgundy</color_swatch>
</size>
<size description="Large">
<color_swatch image="red_cardigan.jpg">Red</color_swatch>
<color_swatch image="burgundy_cardigan.jpg">Burgundy</color_swatch>
</size>
</catalog_item>
<catalog_item gender="Women's">
<item_number>RRX9856</item_number>
<price>42.50</price>
<size description="Small">
<color_swatch image="red_cardigan.jpg">Red</color_swatch>
<color_swatch image="navy_cardigan.jpg">Navy</color_swatch>
<color_swatch image="burgundy_cardigan.jpg">Burgundy</color_swatch>
</size>
<size description="Medium">
<color_swatch image="red_cardigan.jpg">Red</color_swatch>
<color_swatch image="navy_cardigan.jpg">Navy</color_swatch>
<color_swatch image="burgundy_cardigan.jpg">Burgundy</color_swatch>
<color_swatch image="black_cardigan.jpg">Black</color_swatch>
</size>
<size description="Large">
<color_swatch image="navy_cardigan.jpg">Navy</color_swatch>
<color_swatch image="black_cardigan.jpg">Black</color_swatch>
</size>
<size description="Extra Large">
<color_swatch image="burgundy_cardigan.jpg">Burgundy</color_swatch>
<color_swatch image="black_cardigan.jpg">Black</color_swatch>
</size>
</catalog_item>
</product>
</catalog>

我使用了这个命令

xml_split -c /catalog/product[@type='cloths'] products.xml

但它会在没有 XPath 过滤的情况下重现完整的 XML 文档。

最佳答案

好吧,如果我没听错的话,您正在考虑将产品类型分成单独的文件。

我可能会这样做,使用 XML::Twig :

#!/usr/bin/env perl
use strict;
use warnings;

use XML::Twig;

sub split_product {
my ( $twig, $product ) = @_;
open( my $output, '>>', $product->att('type') . ".xml" ) or warn $!;
print {$output} $product->sprint;
$twig -> purge;
}

my $twig = XML::Twig->new(
pretty_print => 'indented_a',
twig_handlers => { 'product' => \&split_product }
);
$twig->parsefile('source.xml');

但这不会保留 XML 结构,它只是将“产品”元素放入新文件中。 (如果存在多个相同类型的产品,那么这也不是有效的 XML)。

好的,因此给定每种类型的多个产品,有必要遍历该文件。这使得事情变得更加复杂,因为在知道 XML 中需要什么之前,您无法“关闭”XML,这意味着您可能需要遍历树两次。

解决此问题的更简单(内存密集型)方法是:

#!/usr/bin/env perl
use strict;
use warnings;

my %products;

use XML::Twig;

sub split_product {
my ( $twig, $product ) = @_;
my $type = $product->att('type');
if ( not $products{$type} ) {
my $new_product = XML::Twig->new;
$new_product->set_root( XML::Twig::Elt->new('catalogue') );
$new_product->set_xml_version('1.0');
$new_product->set_encoding('utf-8');
$new_product->set_doctype('catalog SYSTEM "catalog.dtd"');
$products{$type} = $new_product;
}
$product->cut;
$product->paste( 'last_child', $products{$type}->root );
$twig->purge;
}

my $twig = XML::Twig->new(
pretty_print => 'indented_a',
twig_handlers => { 'product' => \&split_product }
);
$twig->parsefile ( 'your_file.xml' );

foreach my $product_type ( keys %products ) {
open ( my $output, '>', "$product_type.xml" ) or warn $!;
print {$output} $products{$product_type}->sprint;
}

这会将其分割成单独的有效文档,但请注意 - 它将消耗内存中 XML 大小的大约 10 倍。

最后但并非最不重要的 - 一个(希望如此!)内存密集程度较低的版本,使用 flushpurge转储已解析的XML。

#!/usr/bin/env perl
use strict;
use warnings;

my %products;
my %product_files;

use XML::Twig;

sub split_product {
my ( $twig, $product ) = @_;
my $type = $product->att('type');
if ( not $products{$type} ) {
my $new_product = XML::Twig->new;
$new_product->set_root( XML::Twig::Elt->new('catalogue') );
$new_product->set_xml_version('1.0');
$new_product->set_encoding('utf-8');
$new_product->set_doctype('catalog SYSTEM "catalog.dtd"');
$products{$type} = $new_product;
open( $product_files{$type}, '>', "$type.xml" ) or warn $!;
}
$product->cut;
$product->paste( 'last_child', $products{$type}->root );
$twig->purge;
$products{$type}->flush( $product_files{$type} );
}

my $twig = XML::Twig->new(
pretty_print => 'indented_a',
twig_handlers => { 'product' => \&split_product }
);
$twig->parsefile ( 'your_file.xml' );

foreach my $product_type ( keys %products ) {
$products{$product_type}->flush( $product_files{$product_type} );
close( $product_files{$product_type} );
}

如果您只想选择一种特定类型,我们可以在脚本中设置它:

my $target_type = 'cloths'; 

或者从@ARGV(命令行参数)读取它。

my ( $target_type ) = @ARGV; 

然后将“twig_handler”设置为:

"product[\@type=\"$target_type\"]" => \&split_product

尽管这意味着从内存中清除数据的频率会降低。因此,您可以添加到处理程序中:

if ( $product -> att('type') eq $target_type ) { 
$twig -> purge;
return;
}

关于xml - 使用 xml_split 根据 Perl 正则表达式或 XPath 表达式拆分 XML 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34551501/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com