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

问题描述:

I'm currently trying to fetch the data of a simple XML-Sheet which contains data for translation use it's structured like this:

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

Sometimes there are comments after to describe the content a bit more for the translator. I'd like to get those, while I managed to write a comment, I couldn't manage to get 1 comment reliable ...

My idea is: If I want to get a comment of "action_setting" for example I use xpath to select this area:

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

I already tried archieving this with this code:

<?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." ");
    }
?>

As you can see the commented line is simply selecting every comment node after my specific element and picks the first one in row. The problem with this is that I can't make sure that the comment is really after the specific element or just the comment of an element a few lines later.(so if I'd like to get "action_error" it would give me "Comment 2" which belongs to "action_menu)

As you can see I tried already to select this desired area but it simply doesn't return anything when there's a comment.(My source: XPath select all elements between two specific elements)

So I'd be grateful if you would explain me a solution for this problem I'm facing with comments between 2 specific elements.

我目前正在尝试获取一个简单的XML-Sheet的数据,其中包含用于翻译的数据,它的结构类似于 这个: p>

 &lt; string name =“action_settings”&gt;设置&lt; / string&gt;&lt;! -  Comment1  - &gt; 
&lt; string name =“action_error”  &gt;出了点问题。&lt; / string&gt; 
&lt; string name =“action_menu”&gt;您可以选择&lt; / string&gt;&lt;! -  Comment2  - &gt; 
  code>   pre> 
 
 

有时候会有一些评论来为翻译者描述一些内容。 我想得到那些,而我设法写评论,我无法得到1 评论可靠... p>

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

 &lt; string name =“action_settings”&gt;设置&lt; / string&gt; | AREASTART |&lt;! -  Comment1  - &gt; 
 | AREAEND |&lt; string name =“action_error”&gt; Something 出错了。&lt; / string&gt; 
&lt; string name =“action_ 菜单“&gt;您已经有了选择&lt; / string&gt;&lt;! -  Comment2  - &gt; 
  code>  pre> 
 
 

我已经尝试使用此代码实现此目的: p>

 &lt;?php 
 $ doc = new DOMDocument(); 
 $ doc-&gt; load('strings.xml'); 
 
 $ xpath  = new DOMXPath($ doc); 
 
 // foreach($ xpath-&gt; query(“// string [@ name ='debug'] / following :: comment()[1]”)as $ comment  )
 foreach($ xpath-&gt; query(“/ * / string [count(preceding-sibling :: string [@ name ='debug'])= 1] / comment()[1]”)作为$ comment  )
 {
 var_dump($ comment-&gt; textContent。“”); 
} 
?&gt; 
  code>  pre> 
 
 

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

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

所以,如果您能解释我遇到的这个问题的解决方案,我将不胜感激,我将面对2个特定元素之间的评论。 p> div>

You could use following-sibling in conjunction with a predicate.

Get the text of the next comment

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

Given a context node, for example the string with the name of action_settings:

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

    Selects all of the string and comment sibling nodes following the context.

  • [1]

    Filters the node set to have all of the nodes' position() is 1: in other words, it reduces the set to only the first node.

  • [self::comment()]

    Filters the node set to have only comment nodes.

In summary, the above will return a node set consisting of either:

  • A single comment node; the one we are interested in.
  • An empty node set.

Putting it to use in an example

<?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}
";
    echo "Value:   {$value}
";
    echo "Comment: {$comment }

";
}

The real work is done by $next_comment_xpath which uses the example location path given above. The normalize-space() is used two cast the node set to a string, for two reasons: firstly, casting to a string gets us the text content of the first node in the set, or an empty string if none and, secondly, it means evaluate() can return a PHP string.

Example output

Name:    action_settings
Value:   Settings
Comment: Comment1

Name:    action_error
Value:   Error
Comment: 

Name:    action_menu
Value:   Menu
Comment: Comment2