Reputation: 364
I've read some others topics here but this doesn't fit to my sample. I have an XML file where I want to find and replace specific values.
My script is working with expecting result, but it's quite ugly because I don't use all reassources from the module.
I've tried with $node->setData($content);
and $dom->toFile($filename)
but without successful.
Question:
The goal is to find the id from the Media (line 29 column 20 from the XML sample) in order to replace it by $mediaIdFrom
with a better way using the module without open/close files.
Here the script:
#!/usr/bin/perl
use strict;
use warnings 'all';
use autodie;
use feature 'say';
use XML::LibXML;
my $mediaIdFrom = "MEDIAID_TEST";
my $VodItemIdFrom = "VODITEM_ID_TEST";
my $filename = 'sample.xml';
my $out_filename = $filename . ".new";
my $dom = XML::LibXML -> load_xml(location => $filename);
my $mediaId = join '', map { $_->{id}; } $dom->findnodes('/ScheduleProvider/Episode/Media');
my $vodItemId = join '', map { $_->{id}; } $dom->findnodes('/ScheduleProvider/VodItem');
if (-e $filename) {
open(IN, "<", $filename);
open(OUT, ">", $out_filename);
while (<IN>) {
chomp;
$_ =~ s/\"$mediaId\"/\"$mediaIdFrom\"/g if /$mediaId/;
$_ =~ s/\"$vodItemId\"/\"$VodItemIdFrom\"/g if /$vodItemId/;
say $_;
say OUT $_;
}
close(IN);
close(OUT);
}
Here the sample:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<ScheduleProvider id="TST" name="SHOP" scheduleDate="2018-07-05T23:05:45Z">
<Product action="override" endPurchase="2018-08-04T21:59:00Z" endValidity="2018-09-05T03:31:00Z" id="TSTP937279650001" regions="Country" rentalDuration="2611920" startPurchase="2018-07-05T16:27:00Z" startValidity="2018-07-05T16:27:00Z" type="single">
<Price currency="EUR" startPurchase="2018-07-05T16:27:00Z" endPurchase="2018-08-04T21:59:00Z">0.00</Price>
<EpgDescription locale="fr_FR">
<EpgElement key="Title">NO TITLE</EpgElement>
</EpgDescription>
</Product>
<Series id="TST903350550001" action="override" title="Seasons - S1">
<EpgDescription locale="fr_FR">
<EpgElement key="Title">Seasons - S1</EpgElement>
<EpgElement key="Synopsis">Smart</EpgElement>
<EpgElement key="ShortTitle">Seasons - S1</EpgElement>
</EpgDescription>
<EpgDescription>
<EpgElement key="Aspect">16:9</EpgElement>
<EpgElement key="PromoImage">TST_ANT_1192194.jpg</EpgElement>
</EpgDescription>
</Series>
<Episode action="override" duration="1080" id="TST937279650001" title="Épisode 9" number="9" episodeList="9" seriesRef="TST903350550001">
<EpgDescription locale="fr_FR">
<EpgElement key="Title">Épisode 9</EpgElement>
<EpgElement key="Synopsis">George</EpgElement>
</EpgDescription>
<EpgDescription>
<EpgElement key="Aspect">16:9</EpgElement>
<EpgElement key="PromoImage">TST_ANT_1192194.jpg</EpgElement>
</EpgDescription>
<Media id="TSTM937279650001" fileName="TSTM937279650001.ts" frameDuration="27000" fileSize="477380316"/>
</Episode>
<VodItem action="override" contentRef="TST937279650001" id="TSTV937279650001" nodeRefs="TSTFRA1001" previewDate="2016-01-05T16:27:00Z" productRefs="TSTP937279650001" title="Épisode 9" broadcasterId="TST">
<EpgDescription>
<EpgElement key="Studio">Replay</EpgElement>
</EpgDescription>
<EpgDescription locale="fr_FR">
<EpgElement key="Title">Épisode 9</EpgElement>
<EpgElement key="Synopsis">George</EpgElement>
</EpgDescription>
<Period start="2018-07-05T16:27:00Z" end="2018-08-04T21:59:00Z"/>
</VodItem>
</ScheduleProvider>
Upvotes: 0
Views: 587
Reputation: 126722
This will do what you want. You just needed to call setAttributes
on the elements that you had located with findnodes
use strict;
use warnings 'all';
use XML::LibXML;
my $filename = 'sample.xml';
my $out_filename = "$filename.new";
my $media_id_from = 'MEDIAID_TEST';
my $vod_item_id_from = 'VODITEM_ID_TEST';
my $doc = XML::LibXML->load_xml(location => $filename);
my ($media) = $doc->findnodes('/ScheduleProvider/Episode/Media');
$media->setAttribute(id => $media_id_from);
my ($vod_item) = $doc->findnodes('/ScheduleProvider/VodItem');
$vod_item->setAttribute(id => $vod_item_id_from);
$doc->toFile($out_filename);
Upvotes: 2
Reputation: 4013
An attribute node can be got by giving the attribute name preceded by an @ as the last element of the XPath, so change
my $mediaId = join '', map { $_->{id}; } $dom->findnodes('/ScheduleProvider/Episode/Media');
my $vodItemId = join '', map { $_->{id}; } $dom->findnodes('/ScheduleProvider/VodItem');
to
foreach my $attribute ($dom->findnodes('/ScheduleProvider/Episode/Media/@id') {
$attribute->setValue($mediaIdFrom);
}
foreach my $attribute ($dom->findnodes('/ScheduleProvider/VoidItem/@id') {
$attribute->setValue($VodItemIdFrom);
}
This will iterate over each id attribute node allowing you to update the attribute using the setValue()
method.
Then you should be able to use the toFile()
method on the dom object to write out the updated version without having to reopen the input file file
Upvotes: 1