1

我目前正在尝试获取包含用于翻译的数据的简单 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”,它会给我“属于“action_menu”的评论2”

如您所见,我已经尝试选择这个所需的区域,但是当有评论时它根本不返回任何内容。(我的来源:XPath 选择两个特定元素之间的所有元素

因此,如果您能通过 2 个特定元素之间的评论向我解释我面临的这个问题的解决方案,我将不胜感激。

4

1 回答 1

1

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

获取下一条评论的文本

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

给定一个上下文节点,例如stringwith nameof 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
于 2013-11-08T14:03:06.590 回答