我需要使用可选的属性值将xml代码分隔为两个单独的文件。我更喜欢使用Perl。
来使用XML :: LibXML DOM方法Sample XML code excerpt:
...
<LocalJMS>
<Name>ZLAT</Name>
<PrimaryConnection>
<Address string="ops">ops.zla</Address>
<Address string="spt">spt.zla</Address>
<Port>77777</Port>
</PrimaryConnection>
<SecondaryConnection string="ops">
<Address>abc.zla</Address>
<Port>77777</Port>
</SecondaryConnection>
</LocalJMS>
所需的两个最终xml文件将是:
1.) OPS file:
...
<LocalJMS>
<Name>ZLAT</Name>
<PrimaryConnection>
<Address>ops.zla</Address>
<Port>77777</Port>
</PrimaryConnection>
<SecondaryConnection>
<Address>abc.zla</Address>
<Port>77777</Port>
</SecondaryConnection>
</LocalJMS>
2.) SPT file:
...
<LocalJMS>
<Name>ZLAT</Name>
<PrimaryConnection>
<Address>spt.zla</Address>
<Port>77777</Port>
</PrimaryConnection>
</LocalJMS>
在生成两个最终的xml文件之前删除属性没有问题/问题,对于没有子元素的属性做出决定也没有任何问题 - 我可以处理那个当我遍历DOM树并检查子节点时,xml内容到正确的最终xml文件。
但我遇到的问题是在子元素中定义属性的时候(例如'SecondaryConnection',它是'LocalJMS'的子节点)。 如果我“走”DOM树,我将首先遇到父元素'LocalJMS',我需要它的一些子元素(例如'Name','PrimaryConnection')去两个最终文件,但后来我只需要'SecondaryConnection'元素只能转到OPS xml文件(不是SPT文件)。 [btw,该属性适用于所有子节点,即'Address'&amp; '端口']
我正在寻找一些想法 - 可能使用parse_balanced_chunk或从最初的xml文件的最深部分开始工作并向外工作,循环到每个子节点。我讨厌必须使用传统的grep模式等,并将xml文件视为一个简单的文本文件 - 我希望利用DOM方法。
答案 0 :(得分:0)
我建议您解析原始XML,然后对于string
属性的每个值,您可以克隆整个文档,并删除所有具有string
的任何值的属性的元素。需要的那个
看起来像这样。我相信你能够在必要时将输出更改为更合适的输出
use strict;
use warnings 'all';
use XML::LibXML;
my $dom = XML::LibXML->load_xml( location => 'sample.xml' );
for my $string ( qw/ ops spt / ) {
print "\$string = $string\n\n";
my $copy = $dom->cloneNode(1);
for my $unwanted ( $copy->findnodes("//*[\@string != '$string']") ) {
my $parent = $unwanted->parentNode;
$parent->removeChild($unwanted);
}
print $copy, "\n\n---\n\n";
}
$string = ops
<?xml version="1.0"?>
<LocalJMS>
<Name>ZLAT</Name>
<PrimaryConnection>
<Address string="ops">ops.zla</Address>
<Port>77777</Port>
</PrimaryConnection>
<SecondaryConnection string="ops">
<Address>abc.zla</Address>
<Port>77777</Port>
</SecondaryConnection>
</LocalJMS>
---
$string = spt
<?xml version="1.0"?>
<LocalJMS>
<Name>ZLAT</Name>
<PrimaryConnection>
<Address string="spt">spt.zla</Address>
<Port>77777</Port>
</PrimaryConnection>
</LocalJMS>
---
[Finished in 0.8s]
答案 1 :(得分:-2)
它不是您想要的XML解析,但似乎适用于您的示例数据。具有string="filename"
属性的标记仅包含该文件(其中文件名为大写),并删除了string
属性。所有其他标签都会进入所有文件:
my $input=join"",<DATA>;
my @string=$input=~/ string="(\w+)"/g;
for my $s (@string){
my $output=$input;
$output=~
s{ (\s*) <(\w+)\s* ([^>]*?) string="(\w+)" (.*?</\2>) }
{ $4 eq $s ? "$1<$2$3$5" : "" }gsex;
open my $FH, '>', uc($s) or die;
print $FH $output;
close($FH)
}
__DATA__
<LocalJMS>
<Name>ZLAT</Name>
<PrimaryConnection>
<Address string="ops">ops.zla</Address>
<Address string="spt">spt.zla</Address>
<Port>77777</Port>
</PrimaryConnection>
<SecondaryConnection string="ops">
<Address>abc.zla</Address>
<Port>77777</Port>
</SecondaryConnection>
</LocalJMS>
输出:
$ cat OPS
<LocalJMS>
<Name>ZLAT</Name>
<PrimaryConnection>
<Address>ops.zla</Address>
<Port>77777</Port>
</PrimaryConnection>
<SecondaryConnection>
<Address>abc.zla</Address>
<Port>77777</Port>
</SecondaryConnection>
</LocalJMS>
$ cat SPT
<LocalJMS>
<Name>ZLAT</Name>
<PrimaryConnection>
<Address>spt.zla</Address>
<Port>77777</Port>
</PrimaryConnection>
</LocalJMS>