xml - 根据数组中数据的匹配更新 XML 文件的特定节点

标签 xml perl text

我对 Perl 还很陌生。我想更新此 XML 文件中与我从文本文件中读取的值相匹配的特定节点值 LocationID

示例 XML 文件

<?xml version="1.0" encoding="UTF-8"?>
<TestImportFile xmlns="urn:TestImportFile-schema">
    <LOCATION SOURCEID="Yes">
        <LOCATIONID>F16-000100</LOCATIONID>
        <LOCATIONCATEGORY>UFO ABDUCTEE</LOCATIONCATEGORY>
        <LOCAL BIT="Test Case File">
            <LOCALNAME>DTG2QP</LOCALNAME>
            <ASSIGNEDTO>BearmanJ</ASSIGNEDTO>
            <ASSIGNEDTODATETIME>2016-02-02T07:59:00</ASSIGNEDTODATETIME>
            <CASE>
                <CASEVALUE>21</CASEVALUE>
            </CASE>
            <CASE>
                <CASEVALUE>35</CASEVALUE>
            </CASE>
        </LOCAL>
        <LOCAL BIT="Test Case File">
            <LOCALNAME>F4T2557</LOCALNAME>
            <READINGBY>BearmanJ</READINGBY>
            <READINGDATETIME>2016-04-03T06:48:00</READINGDATETIME>
            <CASE>
                <CASEVALUE>83</CASEVALUE>
            </CASE>
            <CASE>
                <CASEVALUE>40</CASEVALUE>
            </CASE>
        </LOCAL>
    </LOCATION>
    <LOCATION SOURCEID="Yes">
        <LOCATIONID>F16-000101</LOCATIONID>
        <LOCATIONCATEGORY>UFO ABDUCTEE</LOCATIONCATEGORY>
        <LOCAL BIT="Test Case File">
            <LOCALNAME>ZGV4TF</LOCALNAME>
            <ASSIGNEDTO>BearmanJ</ASSIGNEDTO>
            <ASSIGNEDTODATETIME>2016-02-02T07:59:00</ASSIGNEDTODATETIME>
            <CASE>
                <CASEVALUE>34</CASEVALUE>
            </CASE>
            <CASE>
                <CASEVALUE>67</CASEVALUE>
            </CASE>
        </LOCAL>
        <LOCAL BIT="Test Case File">
            <LOCALNAME>E5Y7456</LOCALNAME>
            <READINGBY>BearmanJ</READINGBY>
            <READINGDATETIME>2016-04-03T06:48:00</READINGDATETIME>
            <CASE>
                <CASEVALUE>53</CASEVALUE>
            </CASE>
            <CASE>
                <CASEVALUE>20</CASEVALUE>
            </CASE>
        </LOCAL>
    </LOCATION>
    <LOCATION SOURCEID="Yes">
        <LOCATIONID>F16-000102</LOCATIONID>
        <LOCATIONCATEGORY>UFO ABDUCTEE</LOCATIONCATEGORY>
        <LOCAL BIT="Test Case File">
            <LOCALNAME>ZGV4TF</LOCALNAME>
            <ASSIGNEDTO>BearmanJ</ASSIGNEDTO>
            <ASSIGNEDTODATETIME>2016-02-02T07:59:00</ASSIGNEDTODATETIME>
            <CASE>
                <CASEVALUE>34</CASEVALUE>
            </CASE>
            <CASE>
                <CASEVALUE>67</CASEVALUE>
            </CASE>
        </LOCAL>
        <LOCAL BIT="Test Case File">
            <LOCALNAME>E5Y7456</LOCALNAME>
            <READINGBY>BearmanJ</READINGBY>
            <READINGDATETIME>2016-04-03T06:48:00</READINGDATETIME>
            <CASE>
                <CASEVALUE>53</CASEVALUE>
            </CASE>
            <CASE>
                <CASEVALUE>20</CASEVALUE>
            </CASE>
        </LOCAL>
    </LOCATION>
</TestImportFile>

示例文本文件

  F16-000100:2B-16-NOR-0005-J3
  F16-000101:2B-16-NOR-0005-J4
  F16-000102:2B-16-NOR-0005-J5

我可以将测试文件读入数组,但无法确定如何在 XML 文件中搜索匹配项,然后使用所需的值更新 XML 文件中的值。

我的脚本读取文本文件:

my $filename = '1TestData.txt';
open(FILE, $filename) or die "Could not read from $filename, program    halting.";
my $output = '1TestOutput.txt';
open(OUTPUT, '>'.$output) or die "Can't create $output.\n";
while(<FILE>){
    chomp;
    @fields = split(':', $_);
    print "$fields[0]\n";
}
close FILE;

我想将 LOCATIONID 值更新为文本文件中找到的匹配值的第二个值。

<LOCATIONID>F16-000100</LOCATIONID>

期望的结果:

<LOCATIONID>2B-16-NOR-0005-J3</LOCATIONID>

不触及 XML 文件中的任何其他内容。

最佳答案

请不要使用正则表达式。 XML 是上下文相关的,而正则表达式……则不是。

因此考虑到这一点 - 使用解析器。我喜欢XML::Twig ( XML::LibXML 也很不错。XML::Simplediscouraged )

但是您确实有可用的 xpath,它很相似,但更适合它。

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


#parse your file.
my $xml = XML::Twig -> new -> parsefile('sample1.xml');

#open the replacements file for reading
open ( my $input, '<', 'file2.txt') or die $!;
#turn it into key-values for replacement
#probably a bit overkill, as you can just do this iteratively instead. 
my %replace = map { s/\s+//g; split /:/ } <$input>;
close ( $input );

#print for debug
print "Using for replacement:\n ";
print Dumper \%replace;

#iterate all of the search terms
foreach my $search ( keys %replace ) { 
   #use XPATH to find location ID that matches.
   #note - this only finds the _first_ location ID. To do 'all' you'd 
   #need to loop. 
   $xml -> get_xpath("//LOCATIONID[string()=\"$search\"]",0) -> set_text($replace{$search});
}

#set output formatting
$xml -> set_pretty_print('indented_a');
#print to screen
$xml -> print;

#for output:
open ( my $output, '>', 'transformed.xml' ) or die $!;
print {$output} $xml -> sprint;
close ( $output );

如果特定位置 ID 存在多个实例,您需要:

$_ -> set_text($replace{$search}) for $xml -> get_xpath("//LOCATIONID[string()=\"$search\"]");

相反,因为这将搜索与该特定 ID 匹配的所有节点并替换所有节点。

关于xml - 根据数组中数据的匹配更新 XML 文件的特定节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42673128/

相关文章:

java - 如何修改 XML 文件的元素然后打印整个内容

html - 我如何开始使用 Perl 进行 Web 开发?

regex - Perl:查找变量的值是否与数组中的值匹配

php - 如何将 XML 文件插入 WordPress 数据库

android - 解析 XML 时出错 : unbound prefix for mapbox

javascript - 使用 JavaScript 对资源文件中的单引号进行编码以实现自定义操作

perl - 在散列中添加 Getopt::Long 选项,即使使用重复说明符

c - 从C中以分号分隔的文本文件中读取不同的数据

c++ - 如何在文本文件中添加自定义行结尾(例如,我想添加一个在所有句点之后结束的行)

xml - XSLT:如何使用文本节点两次?一次有空格又一次没有空格?