【问题标题】:using variables in perl xpath find statement在 perl xpath find 语句中使用变量
【发布时间】:2025-12-24 21:30:17
【问题描述】:

好的,我一直在四处寻找,似乎找不到我的问题的答案。我正在使用 Perl 使用 XPATH 解析 XML 文件。文件的一部分,不知道子节点会取什么名字。例如:

<state xmlns="http://google.com" id=1>
  <randomName1 type="boolean">0</randomName1>
</state>
<state xmlns="http://google.com" id=2>
  <randomName2 type="boolean">1</randomName2>
</state>

因此,对于每个 randomName,我需要通过执行以下代码来获取我能够做到的名称(注意:我在父 foreach 语句中获取节点列表)。

my $elements = $nodes->getChildNodes;

foreach my $element(@$elements)
{
my $name = (lc($element->getName))
}

当我尝试获取值时,我的问题就出现了,我试图将 my $value = $element-&gt;string_value; 放入 foreach 循环中,而无论名称如何,所做的只是返回 0。我还尝试在 xpath string_value 语句中放置一个变量,但没有成功。

有没有办法将变量放入 xpath 表达式中?类似于(注意:这不起作用)我的$value = $element-&gt;find('$name')-&gt;string_value;

抱歉,如果不清楚,我会尝试回答任何问题,但任何帮助将不胜感激,我已经花了更多时间试图解决这个问题。

【问题讨论】:

  • 我是否正确假设您希望“randomName1”然后是“randomName2”在循环中的 $name 变量中?
  • 是的,没错。如果我打印 "\n $name";变量声明后的语句,它打印子节点的正确名称。
  • 您为此使用了哪些 perl 模块? XPath 在哪里?看起来您只是在使用 XML::DOM。
  • 我没有使用 DOM,只是 XML::XPath
  • 如果可能的话,您应该使用 XML::LibXML。 XML::XPath 更慢、更受限制且没有积极维护。

标签: perl variables xpath find


【解决方案1】:

问题在于,如果文档位于默认名称空间中,则仅在位置步骤中使用元素名称将不会选择任何内容,因为 XPath 将所有未加前缀的名称都视为“无名称空间”。 这是 XPath 中最多的常见问题。只需搜索“XPath 默认命名空间”即可获得答案。

有两种解决方案

  1. 在类似“NamespaceManager”的对象中注册命名空间,然后在 XPath 表达式中使用前缀

  2. 使用定位步骤,例如*[name()='someName']

【讨论】:

  • 在这种情况下,命名空间是任意的。它可以是任何东西,所以我想避免在尝试提取子节点值时使用它。我将努力使位置表达式起作用。谢谢你的建议。
  • @swamprich:如果事先不知道默认命名空间,那么可以使用第二种解决方案。
【解决方案2】:

我推荐使用 XML::XPath 模块:

use XML::XPath;
use XML::XPath::XMLParser;

my $xp = XML::XPath->new(filename => 'test.xml');
my $nodeset = $xp->find('/states/state/*'); # find all subnodes

foreach my $node ($nodeset->get_nodelist) {
    print "FOUND: ", XML::XPath::XMLParser::as_string($node), "\n";
}

使用此示例 XML 文件:

<?xml version="1.0"?>

<states>
<state xmlns="http://google.com" id="1">
  <randomName1 type="boolean">0</randomName1>
</state>
<state xmlns="http://google.com" id="2">
  <randomName2 type="boolean">1</randomName2>
</state>
</states>

这段代码打印:

FOUND: <randomName1 type="boolean">0</randomName1>
FOUND: <randomName2 type="boolean">1</randomName2>

perl+cpan 摇滚!

【讨论】:

  • 谢谢,但拥有完整的输入并不能完全帮助我。我可以很好地获取名称(即randomName1),但未正确解析该值。我可以使用这个并正确的正则表达式,它会删除除值之外的所有内容。感谢您的帮助。
  • 在上面的代码中,$node变量是一个XML::XPath::Node::Element,所以你可以使用它的方法,比如“getAttribute”。看到这个:search.cpan.org/~msergeant/XML-XPath-1.13/XPath/Node/Element.pm
【解决方案3】:

g 前缀绑定到http://google.com 命名空间URI,您可以使用此表达式选择state 的任何子元素:

//g:state/*

注意:如果您知道架构不要以 // 运算符开头的路径,请使用完整路径。

更新:获取每个选中节点的字符串值不是XPath问题,而是宿主语言DOM方法问题。

【讨论】:

    【解决方案4】:

    感谢所有写回复的人,原来我只是个白痴。在我调用子例程的方式中,它只是在每个其他集合上正确传递变量,所以my $value = $element-&gt;string_value; 正在做它的工作并且只返回 0,因为值是 1 的集合正在被传递。

    我很抱歉浪费了任何人的时间……这不是我想给 * 社区留下的第一印象,但再次感谢您的回复。

    【讨论】:

    • 这应该是对您的问题的更新,而不是单独的答案。