XML::LibXML问题:如何查找具有命名空间的XML节点

3

我正在编写一个XML解析器,但在处理链接时遇到了问题。我试图解析XML层次结构中的Settings/Setting,然后查找'Value'节点。以下是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>

这是我用来解析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');
}

当我从XML文件中删除xmlns='http://hme.com/Settings.xsd'时,替换值节点没有问题。但是一旦我将链接重新输入XML中,代码就停止工作,并且无法更新xml表格。有没有一种方法可以处理这个链接或者删除它,以便我可以正确地更新文件?


你可能会发现我教程中的“命名空间处理”部分很有用。 - Grant McLean
看了你提供的页面,我相信我已经正确声明了命名空间,但是出现了 XPath error: Undefined namespace prefix 的错误。我使用了 XPath 沙箱,并能够加载我的 XML 并使用查询来查找节点,但当我尝试在代码中运行时,一无所获。这是我声明命名空间的方式: my $xpc = XML::LibXML::XPathContext->new(); $xpc->registerNs('xsd', 'http://hme.com/Settings.xsd'); - Taylor Stevens
2个回答

3

您要查找命名空间为null且名称为Settings的节点。文档中没有这样的节点,因此findnodes正确地返回了空值。

您想要查找命名空间为http://hme.com/Settings.xsd且名称为Settings的节点。您可以使用以下代码来实现:

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

for ($xpc->findnodes('/s:Settings/s:Setting[@SID="8"]'), $doc) {
   ...
}

0

我使用这段代码成功地实现了它。

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');

如果将来有人需要帮助,请使用此工具,它对我帮助很大。 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
这跟我三天前发布的一样(只不过你用了//代替/,让它变得更糟了)。 - ikegami
@ikegami 抱歉,我把它“搞得更糟了”,我无法使用您的代码使其正常工作。可能是用户错误,我仍在努力学习。 - Taylor Stevens
代码除了两个地方外完全相同:1)您使用了xsd而不是s作为前缀,但前缀的选择并不重要。2)您使用了//而不是/,这是没有必要的非常昂贵的操作,可能会导致错误的结果。 - ikegami
@ikegami 这是我的错,我想说的是今天我不是专家,三年前更不是。 - Taylor Stevens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接