XPath节点到字符串

时间:2010-08-04 19:36:05

标签: php xml xslt xpath simplexml

如何选择以下节点的字符串内容:

<span class="url">
 word
 <b class=" ">test</b>
</span>

<span class="url">
 word
 <b class=" ">test2</b>
 more words
</span>

我尝试了一些事情

//span/text()

没有获得粗体标记

//span/string(.)

无效

string(//span)

仅选择1个节点

我在php中使用simple_xml,我认为唯一的另一个选择是使用// span返回:

Array
(
    [0] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [class] => url
                )

            [b] => test
        )

    [1] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [class] => url
                )

            [b] => test2
        )

)

*请注意,它也会删除第二个范围内的“更多单词”文本。

所以我想我可以使用php在数组中展平项目如何? Xpath是首选,但任何其他想法也会有所帮助。

7 个答案:

答案 0 :(得分:4)

$xml = '<foo>
<span class="url">
 word
 <b class=" ">test</b>
</span>

<span class="url">
 word
 <b class=" ">test2</b>
 more words
</span>
</foo>';
$dom = new DOMDocument();
$dom->loadXML($xml); //or load an HTML document with loadHTML()
$x= new DOMXpath($dom);
foreach($x->query("//span[@class='url']") as $node) echo $node->textContent;

答案 1 :(得分:4)

你甚至不需要XPath:

$dom = new DOMDocument;
$dom->loadHTML($html);
foreach($dom->getElementsByTagName('span') as $span) {
    if(in_array('url', explode(' ', $span->getAttribute('class')))) {
        $span->nodeValue = $span->textContent;
    }
}
echo $dom->saveHTML();

在下方评论后编辑

如果您只想获取字符串,可以执行echo $span->textContent;而不是替换nodeValue。我知道你想要跨度的一个字符串,而不是嵌套的结构。在这种情况下,您还应该考虑在跨度代码段上运行strip_tags是否更快更容易。


使用PHP5.3,您还可以注册任意PHP函数,以用作XPath查询中的回调。以下内容将获取所有span元素及其子节点的内容,并将其作为单个字符串返回。

$dom = new DOMDocument;
$dom->loadHTML($html);
$xp = new DOMXPath($dom);
$xp->registerNamespace("php", "http://php.net/xpath");
$xp->registerPHPFunctions();
echo $xp->evaluate('php:function("nodeTextJoin", //span)');

// Custom Callback function
function nodeTextJoin($nodes)
{
    $text = '';
    foreach($nodes as $node) {
        $text .= $node->textContent;
    }
    return $text;
}

答案 2 :(得分:2)

使用XMLReader:

$xmlr = new XMLReader;
$xmlr->xml($doc);
while ($xmlr->read()) {
    if (($xmlr->nodeType == XmlReader::ELEMENT) && ($xmlr->name == 'span')) {
        echo $xmlr->readString();
    }
}

输出:

word
test

word
test2
more words

答案 3 :(得分:1)

SimpleXML不喜欢将文本节点与其他元素混合,这就是为什么你在那里丢失了一些内容。然而,DOM扩展处理就好了。幸运的是,DOM和SimpleXML是同一枚硬币(libxml)的两个面,因此很容易兼顾它们。例如:

foreach ($yourSimpleXMLElement->xpath('//span') as $span)
{
    // will not work as expected
    echo $span;

    // will work as expected
    echo textContent($span);
}

function textContent(SimpleXMLElement $node)
{
    return dom_import_simplexml($node)->textContent;
}

答案 4 :(得分:0)

//span//text()

这可能是你能做的最好的事情。您将获得多个文本节点,因为文本存储在DOM中的单独节点中。如果你想要一个字符串,你必须自己连接文本节点,因为我想不出一种方法来获得内置的XPath函数。

使用string()concat()将无效,因为这些函数需要字符串参数。将节点集传递给期望字符串的函数时,通过获取节点集中 first 节点的文本内容,将节点集转换为字符串。其余的节点都被丢弃了。

答案 5 :(得分:0)

  

如何选择字符串内容   以下节点:

首先,我认为你的问题不明确。

您可以选择后代文本节点,如John Kugelman回答

//span//text()

我建议使用绝对路径(不是以//开头)

但是有了这个,你需要处理从他们是孩子的父span找到的文本节点。因此,最好只选择span元素(例如//span),然后处理其字符串值。

使用XPath 2.0,您可以使用:

string-join(//span, '.')

结果:

word test. word test2 more words

使用XSLT 1.0,输入:

<div>
<span class="url">
 word
 <b class=" ">test</b>
</span>

<span class="url">
 word
 <b class=" ">test2</b>
 more words
</span>
</div>

使用此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:template match="span[@class='url']">
        <xsl:value-of select="concat(substring('.',1,position()-1),normalize-space(.))"/>
    </xsl:template>
</xsl:stylesheet>

输出:

word test.word test2 more words

答案 6 :(得分:0)

沿着亚历杭德罗的XSLT 1.0“,但任何其他想法也会有所帮助”回答......

<强> XML:

<?xml version="1.0" encoding="UTF-8"?>
<div>
    <span class="url">
        word
        <b class=" ">test</b>
    </span>
    <span class="url">
        word
        <b class=" ">test2</b>
        more words
    </span>
</div>

<强> XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:template match="span">
        <xsl:value-of select="normalize-space(data(.))"/>
    </xsl:template>
</xsl:stylesheet>

<强>输出:

word test
word test2 more words