Как извлечь DOM childNodes или переименовать элемент без использования итерации? - PullRequest
4 голосов
/ 21 февраля 2011
$xml = '<p><a>1</a><b><c>1</c></b></p>';
$dom = new DomDocument;
$dom->loadXML($xml);
$p   = $dom->childNodes->item(0);
echo $dom->saveXML($p);

выше будет печатать обратно

<p>
  <a>1</a>
  <b><c>1</c></b>
</p>

предположим, что необходимо заменить p узел / элемент на new_p что является идеальным способом, кроме как сделать цикл, как показано ниже? (ниже возможно)

$fragment = '';
foreach ($p->childNodes as $a)
{
  $fragment .= $dom->saveXML($a);
}

$new_doc = new DomDocument;
$new_doc->loadXML('<new_node/>');
$f = $new_doc->createDocumentFragment();
$f->appendXML($fragment);
$new_doc->documentElement->appendChild($f);
echo $new_doc->saveXML();

ожидаемые результаты

<new_node><a>1</a><b><c>1</c></b></new_node>

Ответы [ 3 ]

3 голосов
/ 06 марта 2011

Как уже отмечал Марк, манипулировать XML проще всего с XSLT.И вам не нужно писать какие-либо циклы, обдумывание осуществляется процессором XSLT по вашему выбору.

Простые инструкции с XSLT

Вот как может выглядеть XSLT (для некоторых руководств Google предлагает «Идентификационное преобразование XSLT»).

Основы просты: этот тип XSLT-преобразования копирует все как есть, если только нет специального правила (сопоставление с шаблоном в XSLT), которое указывает исключение (в данном случае для <p> элементов).Примечание: не имеет значения, насколько глубоко вложены ваши p-теги, что делает его идеальным для преобразования XML.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <!-- identity transform -->
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- rename "p" with "new_p", copy everything inside p -->
    <xsl:template match="p">
        <new_p>
            <xsl:apply-templates select="@* | node()"/>
         </new_p>
    </xsl:template>

</xsl:stylesheet>

Вызов XSLT из PHP

Это относительно просто, поскольку в PHP есть встроенный модуль для XSL.Вот как вы можете это сделать ( вот дополнительная информация ):

// create an XSLT processor and load the stylesheet as a DOM 
$xproc = new XsltProcessor();
$xslt = new DomDocument;
$xslt->load('yourstylesheet.xslt');    // this contains the code from above
$xproc->importStylesheet($xslt);


// your DOM or the source XML (copied from your question)
$xml = '<p><a>1</a><b><c>1</c></b></p>';
$dom = new DomDocument;
$dom->loadXML($xml);

// do the transformation
if ($xml_output = $xproc->transformToXML($dom)) {
    echo $xml_output;
} else {
    trigger_error('Oops, XSLT transformation failed!', E_USER_ERROR);
} 

Вывод соответствует ожидаемому (дополнительный отступ можно установить с помощью <xsl:output indent="yes"/>:

<new_p>
    <a>1</a>
    <b><c>1</c></b>
</new_p>

Как видите: без циклов и итераций;)

PS: XSLT является широко распространенным и стабильным стандартом.Вам не нужно беспокоиться о правильном экранировании, разборе проблем с разделами или сущностями CDATA, потому что XSLT гарантирует, что вывод будет действительным XML.Это избавляет от головной боли, а не от руки.

2 голосов
/ 05 марта 2011

Разве XSLT не идеален для такого рода операций?

Как переименовать элементы с помощью XSLT

0 голосов
/ 05 марта 2011

Хотя цикл является очевидным решением, определенные ситуации могут предотвратить это или сделать его неприменимым; хотя я не знаю ни одного. В качестве альтернативы это может быть достигнуто путем манипулирования строкой, входной XML-строкой или выходным XML-кодом из метода $new_doc->saveXML(), в зависимости от того, что вы можете использовать. Я бы пошел с str_ireplace или регулярными выражениями, если теги содержат атрибуты, особенно preg_replace с i флагом модификатора для поиска без учета регистра. Я мог бы привести примеры, если вам интересна эта техника.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...