Учитывая PHP-код:
$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);
Я ожидал, что функция traverse () вернется:
This is a link Title with some text following it.
Однако он возвращает только:
Title
Есть ли способ получить ожидаемый результат с помощью simpleXML (очевидно, с целью потребления данных, а не просто возврата его, как в этом простом примере)?
Спасибо, Н.
Могут быть способы добиться того, что вы хотите использовать только SimpleXML, но в этом случае самым простым способом это использовать DOM . Хорошей новостью является то, что если вы уже используете SimpleXML, вам не нужно ничего менять, поскольку DOM и SimpleXML в основном взаимозаменяемы :
// 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; }
node->asXML();// It's the simple solution i think !!
Итак, простой ответ на мой вопрос: 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);
Вы также можете загрузить xml с помощью simpleXML, а затем преобразовать его в DOM, используя dom_import_simplexml (), как сказал Джош. Это было бы полезно, если вы используете simpleXml для фильтрации узлов для синтаксического анализа, например, с помощью XPath.
Тем не менее, я фактически не использую simpleXML, поэтому для меня это займет много времени.
$simpleXml = new SimpleXMLElement($xml); $xmlDom = dom_import_simplexml($simpleXml); print parseTree($xmlDom);
Спасибо вам за помощь!
Вы можете получить текстовый узел элемента DOM с помощью simplexml, просто обработав его как строку:
foreach($xml->children() as $x) { $result .= "$x"
Однако это печатает:
This is a link with some text following it. TitleTitle
… потому что текстовый узел рассматривается как один блок, и нет способа определить, где ребенок помещается внутри текстового узла. Кроме того, дочерний узел добавляется дважды из-за другого {}, но вы можете просто извлечь его.
Извините, если я не очень помог, но я не думаю, что есть какой-то способ узнать, где дочерний узел подходит в текстовом узле, если XML не согласован (но тогда почему бы не использовать теги). Если вы знаете, какой элемент вы хотите удалить из текста, strip_tags()
будет работать отлично.
На это уже был дан ответ, но CASTING TO STRING (т.е. $ sString = (string) oSimpleXMLNode-> TagName) всегда работал для меня.
Как и @tandu, это невозможно, но если вы можете изменить свой XML, это будет работать:
$xml = <<<EOF <articles> <article> This is a link </article> <link>Title</link> <article> with some text following it. </article> </articles>
Попробуй это:
$parser = new SimpleXMLElement($xml); echo strip_tags($parser->asXML());
Это в значительной степени эквивалентно:
$parser = simplexml_load_string($xml); echo dom_import_simplexml($parser)->textContent;