看过各种流行的XML / XPath模块,我还没有看到实现这一目标的直接方法。
基本上界面看起来像:
my $xpath = get_path($node1, $node2);
...将返回从$ node1到$ node2的相对路径。
我将自己的时间用于计算'效率' - 我将采用任何现有的解决方案来解决这个问题。如果做不到这一点,我想知道在任何“明显的”本土解决方案中可能遇到的一些陷阱。
在我的头脑中,我可以想象只是首先在$ node1的后代中搜索$ node2,然后失败,迭代$ node1的祖先做同样的事情。那会不会像我担心的那样充满资源密集型呢?
对于我的特定用例,我可以假设$ node1和$ node2的绝对路径都是已知的。鉴于此,我想认为可以在两条完整路径之间完成一些“XPath数学”,而不必在整个树上运行,但我不知道该过程会是什么样的。
总结一下:
1)现有的CPAN模块是否可以轻松实现我想做的事情?
2)如果没有,那么有什么方法可以解决这个问题?
答案 0 :(得分:6)
找到两个节点的绝对路径。
ref: root foo bar[2] baz[1] moo
target: root foo bar[2] baz[2] moo
删除常见的潜在客户群。
ref: baz[1] moo
target: baz[2] moo
对于参考中的每个细分,在目标前加上..
细分。
.. .. baz[2] moo
转换为XPath。
../../baz[2]/moo
代码:
use XML::LibXML qw( XML_ATTRIBUTE_NODE XML_ELEMENT_NODE );
sub get_path_segs {
my ($node) = @_;
my @path = split(/\//, $node->nodePath());
shift(@path);
return @path;
}
sub get_path {
my ($ref, $targ) = @_;
die if $ref->nodeType() != XML_ELEMENT_NODE && $ref->nodeType() != XML_ATTRIBUTE_NODE;
die if $targ->nodeType() != XML_ELEMENT_NODE && $targ->nodeType() != XML_ATTRIBUTE_NODE;
my @ref = get_path_segs($ref);
my @targ = get_path_segs($targ);
while (@ref && @targ && $ref[0] eq $targ[0]) {
shift(@ref);
shift(@targ);
}
while (@ref) {
pop(@ref);
unshift(@targ, '..');
}
return @targ ? join('/', @targ) : '.';
}
它目前支持元素和属性节点。它可以扩展为支持其他节点类型,可能是平凡的。
答案 1 :(得分:2)
有两种可能的结果
合乎逻辑的行动方针是
在任何一种情况下,生成的路径都是最短的路径。
从父节点链构造相对XPath表达式。找到一个有吸引力的表示甚至可能是整个问题中最难的部分。