【问题标题】:Using XML::Twig, how can I detect the last sibling?使用 XML::Twig,如何检测最后一个兄弟姐妹?
【发布时间】:2012-06-18 08:17:18
【问题描述】:

使用 Perl XML::Twig,我如何在每个兄弟节点上循环直到到达最后一个节点?

while (condition_sibling_TWIG, $v)
{
$v=$v->next_sibling;
$v->print;

# process $v 
}

条件应该是 ($v != undef) 吗?

谢谢

【问题讨论】:

    标签: perl siblings xml-twig nextsibling


    【解决方案1】:

    您可以使用next_siblings 获取兄弟姐妹列表:

    foreach my $sibling ($elt->next_siblings)
      { # process sibling
      }
    

    next_siblings 接受一个可选条件作为参数,它是一个 XPath 步骤,或者至少是 XML::Twig 支持的 XPath 子集:$elt->next_siblings('p[@type="secret"]'))

    【讨论】:

    • 谢谢它完美的工作。但是怎么办,如果我想让 TWIG 继续在下一个元素( SOURCE id="USA" )中寻找 next_siblings:<main> <SOURCE id="AFRICA"> <DEST id="RUSSIA" method="delete"/> <DEST id="USA" method="modify"/> </SOURCE> <SOURCE id="USA"> <DEST id="AUSTRALIA" method="modify"/> <DEST id="CANADA" method="create"/> </SOURCE> </main>
    • -> next_siblings 让我从 DEST 跳到 DEST。但我无法访问第二个元素(“USA”)
    • 看起来您需要导航一个 2 级结构,即 SOURCE 和嵌套的 DEST。您可能需要使用嵌套循环,在 SOURCE 元素上使用外部循环,在 DEST 子元素上使用内部循环。或者在 SOURCE 上有一个处理程序,在 DEST 子级上有一个循环(使用children 方法)。我可能错了,但在我看来,您使用的心智模型并不正确:您需要将 XML 作为树而不是线性数据流来导航。使用children 和(也许)parent 而不是next-sibling
    • 我将修改算法,并在我的实施情况下为您提供更新
    • 因为你不处理第一个孩子,可以吗?如果您需要处理所有这些,您可以将 first_child/siblungs 组合替换为 children。我还将使用 2 个不同的变量,有 2 个名称:一个用于源,一个用于目标。最后,你还可以使用 perl 灵活的引用系统来避免一些反斜杠:$v->next_elt( qq{city[\@id="$tot"]})
    【解决方案2】:

    更新:

    sibling 方法返回下一个兄弟,如果没有剩余兄弟,则返回 undef。您可以使用它来获取下一个,直到没有剩余为止。

    兄弟($offset, $optional_condition)

    Return the next or previous $offset-th sibling of the element, or the $offset-th one matching $optional_condition. If $offset is
    

    如果 $offset 为正,则返回前一个兄弟 然后返回下一个兄弟。 $offset=0 返回元素 if 没有条件或者元素是否匹配条件>, undef 否则。

    这是一个例子:

    use strict; use warnings; 
    use XML::Twig;
    my $t= XML::Twig->new();
    $t->parse(<<__XML__
    <root>
        <stuff>
            <entry1></entry1>
            <entry2></entry2>
            <entry3></entry3>
            <entry4></entry4>
            <entry5></entry5>
        </stuff>
    </root>
    __XML__
    );
    my $root = $t->root;
    my $entry = $root->first_child('stuff')->first_child('entry1');
    while ($entry = $entry->sibling(1)) {
      say $entry->print . ' (' . $entry->path . ')';
    }
    

    这只给你那些你已经拥有的元素之后的元素。如果您从条目 3 开始,您只会得到条目 4 和 5。


    原始(已编辑)答案:

    您还可以使用siblings 方法迭代一个元素的所有兄弟元素的列表。

    兄弟姐妹($optional_condition)

    Return the list of siblings (optionally matching $optional_condition) of the element (excluding the element itself).
    

    元素按文档顺序排列。

    将上面的代码替换为:

    my $root = $t->root;
    my $entry1 = $root->first_child('stuff')->first_child('entry1');
    # This is going to give us entries 2 to 5
    foreach my $sibling ($entry1->siblings) {
      say $sibling->print . ' (' . $sibling->path . ')';
    }
    

    这为您提供了起始元素的所有兄弟姐妹,但不是那个本身。如果您从 entry3 开始,您将获得条目 1、2、4 和 5。

    【讨论】:

    • 我应该使用:foreach my $sibling ($entry1->siblings) {say $sibling->print 。 ' (' . $sibling->path . ')'; OR while ($entry = $entry->sibling(1)) { 说 $entry->print 。 ' (' . $entry->path . ')';
    • 你可以选择你喜欢的,或者像@mirod建议的那样使用next_siblings而不是siblings。由你决定。但是,如果您只想要文档中之后出现的兄弟姐妹,则带有sibling(1)while-loop 或带有next_siblingsforeach-loop 是一种方法去。我相应地改变了答案。
    猜你喜欢
    • 2014-07-12
    • 1970-01-01
    • 1970-01-01
    • 2012-07-23
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-06
    • 2019-08-29
    相关资源
    最近更新 更多