在2个特定元素之间进行选择,以在结束标记和开始标记之间获得注释


Selecting between 2 specific elements to get comments between closing and starting tag

我目前正在尝试获取一个简单的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 -->

有时,后面会有一些评论,为译者描述更多的内容。我想得到这些,虽然我设法写了一条评论,但我没能得到一条可靠的评论。。。

我的想法是:例如,如果我想得到一个"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"的"Comment 2"(

正如你所看到的,我已经尝试过选择这个想要的区域,但当有评论时,它根本不会返回任何内容。(我的来源:XPath选择两个特定元素之间的所有元素(

因此,如果你能向我解释我面临的这个问题的解决方案,并在两个特定元素之间发表评论,我将不胜感激。

您可以将following-sibling与谓词结合使用。

获取下一条评论的文本

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

给定上下文节点,例如具有action_settings:的namestring

  • (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