3

I am writing an XML parser and am having an issue with the program handling a link. I am attempting to parse an XML hierarchy Settings/Setting then findnode 'Value'. The following is an example of the XML:

<?xml version='1.0' ?>
<Settings xmlns='http://hme.com/Settings.xsd'>
  <Setting SID="0">
    <Name>Store ID</Name>
    <Value>72</Value>
  </Setting>
  <Setting SID="1">
    <Name>Deprecated</Name>
    <Value>0</Value>
  </Setting>
  <Setting SID="8">
    <Name>Open Store Hours Sunday</Name>
    <Value>25200</Value>
  </Setting>

Here is the code I am using to parse the XML

my $doc = $parser->parse_file($settings_file) or die "Couldn't parse timer settings\n";

#Sunday
for my $reviewer ($doc->findnodes('/Settings/Setting[@SID="8"]')) {
  my ($name) = $reviewer->findnodes('Value');
  $name->removeChildNodes();
  $name->appendText('109800');
}

When I remove the xmlns='http://hme.com/Settings.xsd' from the XML file, there is no issue with replacing the value node. Once I enter the link back in the XML, the code stops working and will not update the xml sheet. Is there a way to handle for this link or to remove it so I can properly update the file?

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • You might find the "[Working with namespaces](http://grantm.github.io/perl-libxml-by-example/namespaces.html)" section from my tutorial useful. – Grant McLean Jan 28 '20 at 20:05
  • Looking over the page you suggested I believe I am declaring the namespace correcr but am getting an `XPath error: Undefined namespace prefix`. I used the xpath sandbox and was able to load in my xml and use the query to find the node but when I attempt in my code no luck. This is how im declaring the namespace `my $xpc = XML::LibXML::XPathContext->new(); $xpc->registerNs('xsd', 'http://hme.com/Settings.xsd');` – Taylor Stevens Jan 30 '20 at 16:11

2 Answers2

3

You ask to find nodes with namespace null and with name Settings. There are no such nodes in the document, so findnodes correctly returns nothing.

You want to find the nodes with namespace http://hme.com/Settings.xsd and with name Settings. You can use the following to achieve that:

my $xpc = XML::LibXML::XPathContext->new();
$xpc->registerNs( s => 'http://hme.com/Settings.xsd' );

for ($xpc->findnodes('/s:Settings/s:Setting[@SID="8"]'), $doc) {
   ...
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
0

I was able to get this working using this code.

my $dom = XML::LibXML->load_xml(location => $filename);

my $xpc = XML::LibXML::XPathContext->new($dom);
$xpc->registerNs('xsd',  'http://hme.com/Settings.xsd');

my($match1) = $xpc->findnodes('//xsd:Settings/xsd:Setting[@SID="8"]/xsd:Value');
$match1->removeChildNodes();
$match1->appendText('23400');
  • If anyone is looking at this in the future and needs help, this tool helped me alot. https://grantm.github.io/perl-libxml-by-example/_static/xpath-sandbox/xpath-sandbox.html?q=//dublin%3Atitle;filename=xml-libxml.svg;xmlns:dublin=http://purl.org/dc/elements/1.1/ – Taylor Stevens Jan 30 '20 at 19:30
  • That's the same thing I posted 3 days earlier (except you made it a lot worse by using `//` instead of `/`). – ikegami Mar 24 '23 at 16:36
  • @ikegami sorry I made it "a lot worse" I wasn't getting it to work with your code. Could be user error, I'm still trying to learn. – Taylor Stevens Apr 12 '23 at 20:11
  • The code is identical except in two places: 1) You used `xsd` instead of `s` as the prefix, but choice of prefix doesn't matter. 2) You used `//` instead of `/`, which is very expensive for no reason, and it could lead to incorrect results. – ikegami Apr 12 '23 at 20:12
  • @ikegami thats my bad I guess, like I said I am no expert today and was even less so 3 years ago. – Taylor Stevens Apr 12 '23 at 20:22