Мне нужно печатать произвольные объекты SimpleXML определенным образом, с особой обработкой узлов атрибутов.
Проблема состоит в том, что элементы и атрибуты SimpleXML, похоже, используют точно такой же класс, узел атрибутов даже претендует на поддержку метода attributes()
, а SimpleXML скрывает свои внутренние компоненты, поэтому, похоже, нет способа рассказать тип узла (короткий генерации XML и репарации его).
Оба дают одинаковый результат:
$element = new SimpleXMLElement('<foo>test</foo>'); echo $element; print_r($element); $element = new SimpleXMLElement('<foo attr="test" />'); echo $element['attr']; print_r($element['attr']);
Есть ли скрытое свойство / метод, который позволяет идентифицировать тип узла в SimpleXML? Эквивалент DOM $node->nodeType
или $node instanceof DOMAttr
? (Я не могу использовать DOM вместо этого, поддержка SimpleXML является основным требованием).
В SimpleXMLElement
нет встроенных свойств, которые позволят вам рассказать об этом отдельно.
Однако, по мнению других, dom_import_simplexml
может быть уместным, однако, эта функция может иногда менять узлы «на лету», например, если вы передаете список дочерних узлов или именованных дочерних узлов, они будут принимать их и превращать в первый элемент.
Если это пустой список, например, никаких атрибутов, возвращаемых из attributes()
или несуществующих именованных дочерних узлов, он выдаст предупреждение о том, что вам был указан недопустимый тип узла:
Предупреждение: dom_import_simplexml (): неверный тип Nodetype для импорта
Поэтому, если вам нужна эта точность с быстрым логическим значением true
/ false
, вот как это работает с Simplexml:
$isElement = $element->xpath('.') == array($element); $isAttribute = $element[0] == $element and $element->xpath('.') != array($element);
Он работает аналогично спискам атрибутов и спискам элементов, о которых я только что писал об этом утром , вам нужно иметь определенные знания о том, что оценивать для чего, поэтому я создал для него чит-лист:
+------------------+---------------------------------------------+ | TYPE | TEST | +------------------+---------------------------------------------+ | Element | $element->xpath('.') == array($element) | +------------------+---------------------------------------------+ | Attribute | $element[0] == $element | | | and $element->xpath('.') != array($element) | +------------------+---------------------------------------------+ | Attributes | $element->attributes() === NULL | +------------------+---------------------------------------------+ | Elements | $element[0] != $element | | | and $element->attributes() !== NULL | +------------------+---------------------------------------------+ | Single | $element[0] == $element | +------------------+---------------------------------------------+ | Empty List | $element[0] == NULL | +------------------+---------------------------------------------+ | Document Element | $element->xpath('/*') == array($element) | +------------------+---------------------------------------------+
Да, есть способ. Ну, ничего элегантного, что вы можете получить через API, но где-то в кишки SimpleXML отслеживает, что это такое, и он создает различия, например, когда вы вызываете такие функции, как getName () или asXML ().
$element = new SimpleXMLElement('<foo>test</foo>'); print_r($element->getName()); print_r($element->asXML()); echo "------------------\n"; $element = new SimpleXMLElement('<foo attr="test" />'); $at = $element['attr']; print_r($at->getName()); print_r($at->asXML()); foo <?xml version="1.0"?> <foo>test</foo> ------------------ attr attr="test"
Ваш код не выиграет конкурс красоты, но по крайней мере вы можете это сделать.
Используя то, что указал палако, может работать такая функция:
function is_attribute($node) { return !($node->asXML()[0] == "<") }
Вам нужны атрибуты SimpleXMLElement :::
function xml_out($el) { $name = $el->getName(); echo '<'. $name; if (count($el->attributes())) { foreach ($el->attributes() as $a=>$v) { echo ' '. ((string)$a) . '="' . htmlspecialchars((string)$v) . '"'; } } echo '>'. (string)$el; if (count($el->children())) { foreach($el->children() as $c) { xml_out($c); } } echo '</'. $name . '>'; }
Может потребоваться немного подстройки.
Есть ли скрытое свойство / метод, который позволяет идентифицировать тип узла в SimpleXML? Эквивалент DOM $ node-> nodeType или $ node instanceof DOMAttr? (Я не могу использовать DOM вместо этого, поддержка SimpleXML является основным требованием)
Ответ – нет … и да. SimpleXML не обладает таким свойством, но вот хорошая новость: SimpleXML и DOM – это две грани одной и той же монеты. (монета – libxml;)) Вам не нужно выбирать тот или иной, вы можете использовать оба! Вы можете превратить SimpleXMLElement
в DOMNode
и наоборот. В вашем случае вы можете сделать что-то вроде:
$element = new SimpleXMLElement('<foo attr="test" />'); $is_attr = (dom_import_simplexml($element['attr'])->nodeType === XML_ATTRIBUTE_NODE);
Если вы часто это делаете или не хотите обрабатывать жонглирование DOM / SimpleXML, вы можете взглянуть на SimpleDOM .
$element = new SimpleDOM('<foo attr="test" />'); $is_attr = ($element['attr']->nodeType() === XML_ATTRIBUTE_NODE);
К сожалению, нет скрытого свойства или метода, который позволяет идентифицировать тип узла в SimpleXML. SimpleXML использует только один класс, и у элементов нет ничего, что указывало бы на их родителей. Если вы попытаетесь найти отражение ниже, вы увидите, что нет ничего, чтобы отличать элемент или атрибут.
$element = new SimpleXMLElement('<foo>test</foo>'); echo ReflectionObject::export($element); $element = new SimpleXMLElement('<foo attr="test">test</foo>'); echo ReflectionObject::export($element['attr']);
Однако, если элемент имеет атрибуты, вы можете обнаружить это. Таким образом, вы должны были бы предположить, что все элементы, прошедшие через, имеют атрибуты. С этим предположением вы могли бы рассказать им обособленно.
$element = new SimpleXMLElement('<foo attr="test">test</foo>'); echo ReflectionObject::export($element); echo ReflectionObject::export($element['attr']);
Это лучшее, что я могу придумать. Помните, что элемент без атрибутов по-прежнему возвращает false с этим.
function isNotAttribute($simpleXML) { return (count($simpleXML->attributes()) > 0); } $element = new SimpleXMLElement('<foo attr="test">test</foo>'); var_dump(isNotAttribute($element)); var_dump(isNotAttribute($element['attr'])); // returns bool(true) bool(false)