2011-02-27 79 views
5

由于PHP代码获取一个节点的文本部分:使用PHP简单的XML

$xml = <<<EOF 
<articles> 
<article> 
This is a link 
<link>Title</link> 
with some text following it. 
</article> 
</articles> 
EOF; 

function traverse($xml) { 
    $result = ""; 
    foreach($xml->children() as $x) { 
     if ($x->count()) { 
      $result .= traverse($x); 
     } 
     else { 
      $result .= $x; 
     } 
    } 
    return $result; 
} 

$parser = new SimpleXMLElement($xml); 
traverse($parser); 

我预期的功能遍历()返回:

This is a link Title with some text following it. 

然而,它只返回:

Title 

有没有办法使用simpleXML来获得预期的结果(显然是为了消费数据而不是仅仅使用r就像在这个简单的例子中一样)?

感谢, N.

回答

15

可能有办法达到你想要只使用了SimpleXML什么,但在这种情况下,最简单的方法是使用DOM。好消息是,如果你已经使用了SimpleXML,你没有任何改变的DOM和SimpleXML是basically interchangeable

// either 
$articles = simplexml_load_string($xml); 
echo dom_import_simplexml($articles)->textContent; 

// or 
$dom = new DOMDocument; 
$dom->loadXML($xml); 
echo $dom->documentElement->textContent; 

假设你的任务是遍历每个<article/>并获得它的内容,你的代码看起来像

$articles = simplexml_load_string($xml); 
foreach ($articles->article as $article) 
{ 
    $articleText = dom_import_simplexml($article)->textContent; 
} 
+0

这实际上产生了我期待的确切结果 - 实际上并没有解决遍历Xml文档的底层问题。 – Nikolaj 2011-02-27 16:28:35

+1

您将无法使用SimpleXML“遍历”或迭代文本节点。或者至少,如果可能的话,它将被设计/不切实际。使用SimpleXML让东西变得更容易,然后将所选节点导入DOM,以访问不属于SimpleXML的功能。 – 2011-02-27 17:08:28

+0

是的,确实如此。看来我必须学习那种困难的方式。 – Nikolaj 2011-02-27 17:17:11

1

您可以只用对待它就像一根绳索让用SimpleXML DOM元素的文本节点:

foreach($xml->children() as $x) { 
    $result .= "$x" 

然而,这种打印出:

This is a link 

with some text following it. 
TitleTitle 

..因为文本节点被视为一个块,并且无法确定子文件在文本节点内的位置。由于其他人{},子节点也被添加了两次,但是您可以将其取出。

对不起,如果我没有什么帮助,但我不认为有什么方法可以找出子节点在文本节点中的位置,除非xml是一致的(但为什么不使用标签)。如果你知道你想剥离文本的元素,strip_tags()将工作得很好。

+0

它总是帮助知道你要完成什么是不可能的。不幸的是,我不拥有XML,所以它就是这样。你知道在php中的其他解析器是否更适合我的任务吗? – Nikolaj 2011-02-27 09:24:18

+0

我不知道任何现有的..也许你可以写一个! – 2011-02-27 14:39:17

+0

在讨论了错误的(解析器?)树之后,似乎DOM是我们需要处理这类XML的朋友。 – Nikolaj 2011-02-27 16:18:13

0

像@tandu说,这是不可能的,但如果你可以改变你的XML,这将工作:

$xml = <<<EOF 
<articles> 
    <article> 
     This is a link 
    </article> 
    <link>Title</link> 
    <article> 
     with some text following it. 
    </article> 
</articles> 
3

所以,我的问题的简单答案是:Simplexml无法处理这种类型的XML。改用DomDocument。

此示例说明如何遍历整个XML。 DomDocument似乎可以用于任何XML,而SimpleXML则要求XML很简单。

function attrs($list) { 
    $result = ""; 
    foreach ($list as $attr) { 
     $result .= " $attr->name='$attr->value'"; 
    } 
    return $result; 
} 

function parseTree($xml) { 
    $result = ""; 
    foreach ($xml->childNodes AS $item) { 
     if ($item->nodeType == 1) { 
      $result .= "<$item->nodeName" . attrs($item->attributes) . ">" . parseTree($item) . "</$item->nodeName>"; 
     } 
     else { 
      $result .= $item->nodeValue; 
     } 
    } 
    return $result; 
} 

$xmlDoc = new DOMDocument(); 
$xmlDoc->loadXML($xml); 

print parseTree($xmlDoc->documentElement); 

你也可以使用SimpleXML加载XML,然后使用dom_import_simplexml()作为乔希说,将其转换为DOM。如果您使用simpleXml过滤节点进行解析,这将非常有用,例如使用XPath。

但是,我实际上并没有使用simpleXML,所以对我来说这将会花费很长时间。

$simpleXml = new SimpleXMLElement($xml); 
$xmlDom = dom_import_simplexml($simpleXml); 

print parseTree($xmlDom); 

谢谢大家的帮助!

4
node->asXML();// It's the simple solution i think !! 
+0

你有没有用OP的数据试过这个?它实际上工作吗? – 2011-08-23 09:51:25

1

这已经被回答了,但CASTING TO STRING(即$ sString =(string)oSimpleXMLNode-> TagName)总是为我工作。

+0

echo(string)$ xmlNode; – 2014-08-22 07:13:18

0

试试这个:

$parser = new SimpleXMLElement($xml); 
echo strip_tags($parser->asXML()); 

这几乎等同于:

$parser = simplexml_load_string($xml); 
echo dom_import_simplexml($parser)->textContent;