Я испытываю следующее поведение:
$xml_string1 = "<person><name><![CDATA[ Someone's Name ]]></name></person>"; $xml_string2 = "<person><name> Someone's Name </name></person>"; $person = new SimpleXMLElement($xml_string1); print (string) $person->name; # Someone's Name $person = new SimpleXMLElement($xml_string2); print (string) $person->name; # Someone's Name $person = new SimpleXMLElement($xml_string1, LIBXML_NOCDATA); print (string) $person->name; # Someone's Name
В документах php говорится, что NOCDATA «Слияние [s] CDATA в виде текстовых узлов». Для меня это означает, что CDATA будет обрабатываться так же, как текстовые узлы, или что поведение третьего примера теперь будет таким же, как второй пример.
Я не контролирую XML (это фид из внешнего источника), иначе я просто удалю тэг CDATA, поскольку он ничего не делает и разрушает поведение, которое я хочу.
Почему приведенный выше пример ведет себя так, как он делает? Есть ли способ заставить SimpleXML обрабатывать узлы CDATA так же, как обрабатывать текстовые узлы? Что делает «Слияние CDATA в виде текстовых узлов» на самом деле, так как я, похоже, не понимаю этот вариант?
Я в настоящее время расшифровываю после того, как вытаскиваю данные, но приведенный выше пример до сих пор не имеет смысла для меня.
Назначение разделов CDATA в XML – это инкапсулировать блок текста «как есть», который в противном случае потребовал бы экранирования специальных символов (в частности, >
, <
и &
). Секция CDATA, содержащая символ &
совпадает с обычным текстовым узлом, содержащим &
,
Если бы синтаксический анализатор предлагал проигнорировать это и притвориться, что все узлы CDATA были действительно просто текстовыми узлами, он мгновенно разорвался, как только кто-то упомянул «Круизы P & O» – &
просто не может быть там сам по себе (а не как &
или &somethingElse;
).
LIBXML_NOCDATA
на самом деле довольно бесполезен для SimpleXML, потому что (string)$foo
аккуратно объединяет любую последовательность текстовых и CDATA-узлов в обычную строку PHP. (То, что люди часто не замечают, потому что print_r
этого не делает.) Это не обязательно относится к более систематическим методам доступа, таким как DOM, где вы можете манипулировать текстовыми узлами и узлами CDATA как самостоятельные объекты.
То, что он эффективно делает, – это пройти через документ, и везде, где он сталкивается с разделом CDATA, он захватывает содержимое, ускоряет его и помещает обратно как обычный текстовый узел или «объединяет» его с любыми текстовыми узлами с обеих сторон. Представленный текст идентичен, просто сохраняется в документе по-другому; вы можете увидеть разницу, если вы экспортируете обратно в XML, как в этом примере:
$xml_string = "<person><name>Welcome aboard this <![CDATA[P&O Cruises]]> voyage!</name></person>"; $person = new SimpleXMLElement($xml_string); echo 'CDATA retained: ', $person->asXML(); // CDATA retained: <?xml version="1.0"?> // <person><name>Welcome aboard this <![CDATA[P&O Cruises]]> voyage!</name></person> $person = new SimpleXMLElement($xml_string, LIBXML_NOCDATA); echo 'CDATA merged: ', $person->asXML(); // CDATA merged: <?xml version="1.0"?> // <person><name>Welcome aboard this P&O Cruises voyage!</name></person>
Если XML-документ, который вы просматриваете, содержит раздел CDATA, который фактически содержит сущности, вам нужно взять эту строку и полностью удалить ее из XML. Одной из распространенных причин сделать это (кроме лени с плохо понимаемыми библиотеками) является обработка чего-то, помеченного в HTML, как любая старая строка внутри XML-документа, например:
<Comment> <SubmittedBy>IMSoP</SubmittedBy> <Text><![CDATA[I'm <em>really</em> bad at keeping my answers brief <tt>;)</tt>]]></Text> </Comment>