在两个特定元素之间进行选择以获得关闭和开始标记之间的注释

时间:2013-11-05 08:14:01

标签: php dom xpath

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

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

有时候会有一些评论来为翻译者描述一些内容。 我想得到那些,而我设法写评论,我无法得到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”它会给我“评论2“属于”action_menu“

正如你所看到的,我已经尝试选择这个想要的区域,但是当有评论时它根本不会返回任何内容。(我的来源:XPath select all elements between two specific elements

所以如果你能解释我面临的这个问题的解决方案,我会感激不已。我会面对两个具体要素之间的评论。

1 个答案:

答案 0 :(得分:1)

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

获取下一条评论的文字

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

给定一个上下文节点,例如string name action_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