使用Perl有条件地向XML文件添加标记

使用Perl有条件地向XML文件添加标记,xml,perl,xml-twig,Xml,Perl,Xml Twig,我不是一个开发者,而是一个网络安全人员。如果元素不存在,我需要为它插入标记和值 下面是我的XML文件的一个片段 <NessusClientData_V2> <Policy> ... <Report> ... <ReportHost name="1.2.3.4"> ... <HostProperties> ...

我不是一个开发者,而是一个网络安全人员。如果元素不存在,我需要为它插入标记和值

下面是我的XML文件的一个片段

<NessusClientData_V2> 
    <Policy> 
    ... 
    <Report> 
    ... 
        <ReportHost name="1.2.3.4"> 
        ... 
            <HostProperties> 
            ... 
                <tag name="HOST_END">Thu Sep 17 17:23:19 2015</tag> 
                <tag name="system-type">general-purpose</tag> 
                <tag name="operating-system">MS WIN</tag> 
                <tag name="ssh-auth-meth">password</tag> 
                <tag name="ssh-login-used">backup</tag> 
                <tag name="local-checks-proto">ssh</tag> 
                <tag name="host-ip">1.2.3.4</tag> 
                <tag name="HOST_START">Thu Sep 17 17:00:14 2015</tag>
            </HostProperties> 
            ...
如果它还没有

“我的输出”需要包含所有原始信息,但只需要添加到中。

您可以使用来完成此操作。下面的代码迭代所有
主机属性
节点,并检查它们是否存在名为
mac地址
标记
,如果不存在,则插入一个

use strict;
use warnings;
use XML::Twig;

# at most one div will be loaded in memory
my $twig = XML::Twig->new(
    twig_handlers => {
        '//ReportHost/HostProperties' => sub {
            my $seen = 0;
            foreach my $elem ( $_->children('tag') ) {
                if ( $elem->atts->{name} eq 'mac-address' ) {
                    $seen++;
                    last;
                }
            }
            $_->insert_new_elt( 
              'last_child', 
              'tag' => { name => 'mac-address' }, 
              'barfoo' 
            ) unless $seen;
        }
    },
    pretty_print => 'indented',
);

$twig->parse( \*DATA );
$twig->flush;

__DATA__
<NessusClientData_V2>
    <Policy>
    <Report>
        <ReportHost name="1.2.3.4">
            <HostProperties>
                <tag name="HOST_END">Thu Sep 17 17:23:19 2015</tag>
                <tag name="system-type">general-purpose</tag>
                <tag name="operating-system">MS WIN</tag>
                <tag name="ssh-auth-meth">password</tag>
                <tag name="ssh-login-used">backup</tag>
                <tag name="local-checks-proto">ssh</tag>
                <tag name="host-ip">1.2.3.4</tag>
                <tag name="HOST_START">Thu Sep 17 17:00:14 2015</tag>
            </HostProperties>
        </ReportHost>
        <ReportHost name="127.0.0.1">
            <HostProperties>
                <tag name="HOST_END">Thu Sep 17 17:23:19 2015</tag>
                <tag name="system-type">general-purpose</tag>
                <tag name="operating-system">MS WIN</tag>
                <tag name="ssh-auth-meth">password</tag>
                <tag name="ssh-login-used">backup</tag>
                <tag name="local-checks-proto">ssh</tag>
                <tag name="host-ip">127.0.0.1</tag>
                <tag name="HOST_START">Thu Sep 17 17:00:14 2015</tag>
                <tag name="mac-address">foobar</tag>
            </HostProperties>
        </ReportHost>
    </Report>
</Policy>
</NessusClientData_V2>
使用严格;
使用警告;
使用XML::Twig;
#内存中最多会加载一个div
my$twig=XML::twig->new(
细枝处理程序=>{
'//ReportHost/HostProperties'=>sub{
我的$SEED=0;
foreach my$elem($\->children('tag')){
如果($elem->atts->{name}eq'mac address'){
$seen++;
最后;
}
}
$\->插入新的英语教学(
“最后一个孩子”,
'tag'=>{name=>'mac address'},
“巴福”
)除非$seen;
}
},
漂亮的打印=>“缩进”,
);
$twig->parse(\*数据);
$twig->flush;
__资料__
2015年9月17日星期四17:23:19
通用型
温女士
密码
备份
ssh
1.2.3.4
2015年9月17日星期四17:00:14
2015年9月17日星期四17:23:19
通用型
温女士
密码
备份
ssh
127.0.0.1
2015年9月17日星期四17:00:14
福巴
您必须将
->parse(\*DATA)
替换为
->parse\u文件
,可能还需要添加一些随机的mac地址。

好吧,我继续回答,再加上一点XML示例,我将循环回答。对于这个技巧,我将使用
xpath
来查询XML,而不是遍历树。这是因为
xpath
允许您在单个语句中查询元素、属性和属性内容

#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;

my $twig = XML::Twig->parsefile( 'your_file.xml' );

#search for "HostProperties" nodes within the tree. You can
#be more specific about this if you need to. 
foreach my $HP ( $twig->get_xpath('//HostProperties') ) {
    #check if it has a "tag" element with a "mac-address" "name" attribute.
    if ( not $HP->get_xpath('./tag[@name="mac-address"]') ) {
        #insert a new element at the end of the entry. 
        $HP->insert_new_elt( 'last_child', 
                     'tag', { 'name' => 'mac-address' },
                     "DE:AD:BE:EF:F0:FF" );
    }
}

#note - pretty printing helps reading, but might
#cause some problems with certain XML constructs. Shouldn't in your specific example though. 
$twig->set_pretty_print("indented_a");
$twig->print;

#to save it to a file:
open ( my $output, '>', 'processed.xml' ) or die $!;
print {$output} $twig -> sprint;
close ( $output ); 

您的问题可能会被关闭为离题,因为您似乎要求为您免费编写一些代码。这有点粗鲁,不是堆栈溢出的原因。你应该读一读“Stack Overflow是为专业和狂热的程序员准备的,他们编写代码是因为他们喜欢它”,这似乎并不适用于你。在任何情况下,我都看不出MAC地址的值来自哪里好的,没关系。我必须把文件上传到一个政府系统,这个系统需要一个愚蠢的mac地址输入,即使这是假的。我一直在努力寻找如何以自动化方式实现这一点的想法。我不是程序员,所以这可能不是最好的论坛。堆栈溢出是一个知识库,不是论坛。可以把它看作是编程问题解决方案的维基百科。通过问一个问题,你正在打开一个你认为属于这里但以前从未创建过的新主题。这是一个跨站点的骗局吗?看起来像@Sobrique。我有一阵子没查过帕尔蒙克斯了。不幸的是,它使我的眼睛受伤了-/我时常这样做。相比之下,它似乎更容易出现“格式错误综合症”。
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;

my $twig = XML::Twig->parsefile( 'your_file.xml' );

#search for "HostProperties" nodes within the tree. You can
#be more specific about this if you need to. 
foreach my $HP ( $twig->get_xpath('//HostProperties') ) {
    #check if it has a "tag" element with a "mac-address" "name" attribute.
    if ( not $HP->get_xpath('./tag[@name="mac-address"]') ) {
        #insert a new element at the end of the entry. 
        $HP->insert_new_elt( 'last_child', 
                     'tag', { 'name' => 'mac-address' },
                     "DE:AD:BE:EF:F0:FF" );
    }
}

#note - pretty printing helps reading, but might
#cause some problems with certain XML constructs. Shouldn't in your specific example though. 
$twig->set_pretty_print("indented_a");
$twig->print;

#to save it to a file:
open ( my $output, '>', 'processed.xml' ) or die $!;
print {$output} $twig -> sprint;
close ( $output );