Сохранить & lt; br & gt; при извлечении XML-текста в Stack Overflow

У меня есть большой XML-файл, который я хочу проанализировать и поместить в базу данных. Например, этот файл:

<aa>
<bb>Some text goes here and <br /> some more on a new line
there are other <junk/> tags that I want to keep ignoring
</bb>
</aa>

Мой код ниже использует SimpleXML для разбора текстового содержимого внутри bb тег, но он молча игнорирует <br /> тег. Как я могу изменить свой код, чтобы принять <br/> но нет <junk/>?

$xml = simplexml_load_file("ab.xml");
foreach( $xml->bb as $bb ) {
// $bb now contains the text content of the element, but no tags
}

1

Решение

Поскольку вы можете точно сказать, какие элементы вы хотите удалить, обычно это проще всего сделать с помощью xpath, запрашивая эти элементы, а затем удаляя их.

В SimpleXML:

$remove = '//junk'; // all <junk> tags anywhere

// simplexml
$sx = simplexml_load_string($xml);
foreach ($sx->xpath($remove) as $element) {
unset($element->{0});
}

В DOMDocument:

$remove = '//junk'; // all <junk> tags anywhere

// dom
$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
foreach ($xpath->query($remove) as $element) {
$element->parentNode->removeChild($element);
}

Полный пример (демонстрация):

<?php
/**
* @link http://stackoverflow.com/a/26318711/367456
* @link https://eval.in/204702
*/

$xml = <<<BUFFER
<aa>
<bb>Some text goes here and <br /> some more on a new line
there are other <junk/> tags that I want to keep ignoring
</bb>
</aa>
BUFFER;

$remove = '//junk'; // all <junk> tags anywhere

// simplexml
$sx = simplexml_load_string($xml);
foreach ($sx->xpath($remove) as $element) {
unset($element->{0});
}
$sx->asXML('php://output');

// dom
$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
foreach ($xpath->query($remove) as $element) {
$element->parentNode->removeChild($element);
}
$doc->save('php://output');

Выход:

<?xml version="1.0"?>
<aa>
<bb>Some text goes here and <br/> some more on a new line
there are other  tags that I want to keep ignoring
</bb>
</aa>
<?xml version="1.0"?>
<aa>
<bb>Some text goes here and <br/> some more on a new line
there are other  tags that I want to keep ignoring
</bb>
</aa>
1

Другие решения

Вы можете удалить теги, если знаете, что хотите сохранить, а какие хотите удалить.

$xml = simplexml_load_file("ab.xml");
foreach( $xml->bb as $bb ) {
// This will strip everything but <br>
echo strip_tags($bb,"<br>");
}
1

Я не смог решить свою проблему с помощью SimpleXML, но мне удалось использовать DOMElement с рекурсивным подходом. Обратите внимание, что критерий выбора тега находится внутри рекурсивной функции.

// SimpleXML can be used for the 'simple' cases
$xml = simplexml_load_file("file.xml");
$dom = dom_import_simplexml($xml);
// simpleXML and DOM works with the same underlying data structure, so you can use them interchangably

$aa_content = $xml->aa;
// using simpleXML, $aa is now: "Some text goes here and some more on a new line there are other tags that I want to keep ignoring"// the <junk> tag is ignore, which is good; but the <br> tag is also ignored, which is bad// the DOM method
foreach( $dom->childNodes as $node ) {
$textContent = parsePreserveTags($node);
}

function parsePreserveTags($domNode) {
// we want to preserve tags (for example, html formatting like <br>)
$result = '';//$domNode->nodeValue;
if( $domNode->hasChildNodes() ) {
foreach( $domNode->childNodes as $node ) {
// The constant XML_ELEMENT_NODE is defined here http://php.net/manual/en/dom.constants.php
// If node type is XML_ELEMENT_NODE it's a tag and it can have children.
// Otherwise, just get the (text) value.
if( $node->nodeType == XML_ELEMENT_NODE ) {
// Throw away nodes that match certain criteria
if( $node->nodeName == 'junk' )
continue;

if( $node->hasChildNodes() ) {
// example: "<p>...</p>"$result .= '<' . $node->nodeName . '>' . parsePreserveTags($node)
. '</' . $node->nodeName . '>';
} else {
// example: "<br/>"$result .= '<' . $node->nodeName . '/>';
}
} else {
// example: plain text node
$result .= $node->nodeValue;
}
}
}
return $result;
}
1
По вопросам рекламы [email protected]