【问题标题】:Selecting between 2 specific elements to get comments between closing and starting tag在 2 个特定元素之间进行选择以获取结束标记和开始标记之间的注释
【发布时间】:2013-11-08 22:03:06
【问题描述】:

我目前正在尝试获取包含用于翻译的数据的简单 XML 表的数据,其结构如下:

<string name="action_settings">Settings</string><!-- Comment1 -->
<string name="action_error">Something went wrong.</string>
<string name="action_menu">You've got the choice</string><!-- Comment2 -->

有时后面会有 cmets 为译者多描述一下内容。 我想得到那些,虽然我设法写了一条评论,但我无法获得 1 条可靠的评论......

我的想法是: 例如,如果我想获得“action_setting”的评论,我使用 xpath 来选择这个区域:

<string name="action_settings">Settings</string>|AREASTART|<!-- Comment1 -->
|AREAEND|<string name="action_error">Something went wrong.</string>
<string name="action_menu">You've got the choice</string><!-- Comment2 -->

我已经尝试使用此代码进行存档:

<?php
    $doc = new DOMDocument();
    $doc->load('strings.xml');

    $xpath = new DOMXPath($doc);

    //foreach ($xpath->query("//string[@name='debug']/following::comment()[1]") as $comment)
    foreach ($xpath->query("/*/string[count(preceding-sibling::string[@name='debug'])=1]/comment()[1]") as $comment)
    {
        var_dump($comment->textContent." ");
    }
?>

如您所见,注释行只是在我的特定元素之后选择每个注释节点并选择行中的第一个。这样做的问题是我无法确保评论真的在特定元素之后,或者只是在几行之后的元素评论。(所以如果我想得到“action_error”,它会给我“属于“action_menu”的评论2”

如您所见,我已经尝试选择此所需区域,但当有评论时它根本不返回任何内容。(我的来源:XPath select all elements between two specific elements

因此,如果您能解释一下我在两个特定元素之间使用 cmets 所面临的问题的解决方案,我将不胜感激。

【问题讨论】:

  • 您能否增强您的第二个示例摘录以实际包含您想要检索的内容?这是为了测试。
  • 添加了 cmets。并用一个例子解释了我第一种获取 cmets 的方法的问题。

标签: php dom xpath


【解决方案1】:

您可以将following-siblingpredicate 结合使用。

获取下一条评论的文字

(following-sibling::string|following-sibling::comment())[1][self::comment()]

给定一个上下文节点,例如stringnameaction_settings

  • (following-sibling::string|following-sibling::comment())

    选择上下文后面的所有string 和注释兄弟节点。

  • [1]

    过滤节点集以使所有节点的position()1:换句话说,它将集合减少到只有第一个节点。

  • [self::comment()]

    过滤节点集以仅包含评论节点。

总之,以上将返回一个节点集,包括:

  • 单个评论节点;我们感兴趣的那个。
  • 一个空节点集。

将其用于示例

<?php

$xml = <<<XML
<example>
    <string name="action_settings">Settings</string><!-- Comment1 -->
    <string name="action_error">Error</string>
    <string name="action_menu">Menu</string><!-- Comment2 -->
</example>
XML;

$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);

$next_comment_xpath = 'normalize-space(
    (following-sibling::string|following-sibling::comment())[1][self::comment()]
)';

$strings = $xpath->query('//string');
foreach ($strings as $string)
{
    $name = $string->getAttribute('name');
    $value = $string->nodeValue;
    $comment = $xpath->evaluate($next_comment_xpath, $string);

    echo "Name:    {$name}\n";
    echo "Value:   {$value}\n";
    echo "Comment: {$comment }\n\n";
}

真正的工作由$next_comment_xpath 完成,它使用上面给出的示例位置路径。 normalize-space() 用于两次将节点集转换为字符串,原因有两个:首先,转换为字符串可以获得集合中第一个节点的文本内容,如果没有则为空字符串,其次,这意味着evaluate() 可以返回一个 PHP 字符串。

示例输出

Name:    action_settings
Value:   Settings
Comment: Comment1

Name:    action_error
Value:   Error
Comment: 

Name:    action_menu
Value:   Menu
Comment: Comment2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-11
    相关资源
    最近更新 更多