Intereting Posts
Как добавить источник html в DOMElement в PHP? Ошибка компиляции: «g ++: ошибка при попытке выполнить« cc1plus »: execvp: нет такого файла или каталога" Каковы преимущества программирования OO? Помогло бы мне написать лучший код? PHP – перенастроить массив по определенному индексу Как преобразовать строки из MySql в массив JSON PHP MySQL INSERT терпит неудачу из-за уникального ограничения kohana 3.2 ORM find_all () с отношениями Как отправить электронную почту с арабским контентом через почтовую функцию PHP? htaccess не переписывает url для моих запросов GET Поиск строки Base64 в таблице MySQL с использованием PHP Получить все переменные $ _POST, начиная с определенного текста Подготовка приложения PHP для использования с UTF-8 Как сказать, когда запрос успешно выполнен в PHP PDO? В чем разница между bindParam и bindValue? Как получить данные из xml в php и создать новую страницу или URL-адрес в php и показать полный контент из xml?

Упростить PHP DOM XML-анализ – как?

Я провел целые дни с функциями DOM PHP, но я не могу понять, как это работает. 🙁 У меня есть простой XML-файл, который выглядит нормально, но я не могу использовать его, как я думаю, когда я создал его структуру.

Пример XML-фрагмента:

-pages //root element -page id="1" //we can have any number of pages -product id="364826" //we can have any number of products -SOME_KIND_OF_VALUE -ANOTHER_VALUE ... 

Моя первоначальная идея состояла в том, чтобы ускорить рабочий процесс моего клиента, поэтому я выбрасываю старые CSV и начинаю использовать XML.

Проблема 1. Когда я группирую продукты на странице, я использую setIdAttribute, чтобы предотвратить сохранение одной и той же страницы в дереве более одного раза. Это отлично работает, пока не происходит чтение, потому что эти идентификаторы привязаны к каким-то DTD (на основе getElementById ).

Вопрос 1: Как я могу написать простой DTD, который предоставляет эти необходимые данные, чтобы я мог использовать getElementById на этапе чтения тоже?

Проблема 2: Поскольку у меня есть страницы, которые я бы хотел загрузить как можно меньше информации. Вот почему я создал атрибут id на страницах. Теперь я не могу получить доступ к моей странице id = "2" напрямую, потому что проблема 1 выше ( getElementById не имеет смысла в настоящее время). Как-то мне удалось получить необходимую информацию о каждом продукте на данной странице, но мой код выглядит страшно:

 $doc = DOMDocument::load('data.xml'); $xpath = new DOMXPath($doc); $query = '/pages/page[' . $page . ']'; //$page is fine: was set earlier $products = $xpath->query($query); $_prods = $doc->getElementsByTagName('product'); foreach($_prods as $product){ foreach($product->childNodes as $node){ echo $node->nodeName . ": " . $node->nodeValue . "<br />"; } } 

Queston 2: Я думаю, что приведенный выше код является примером того, как не анализировать XML. Но из-за моего ограниченного знания функций DOM PHP я не могу написать чище один сам. Я пробовал какое-то тривиальное решение, но никто из них не работал для меня.

Пожалуйста, помогите мне, если сможете.

Спасибо, fabrik

Решение проблемы 1:

W3C определяет : значение атрибута xml:id как атрибут идентификатора в документах XML и определяет обработку этого атрибута для идентификации идентификаторов в отсутствие проверки, без извлечения внешних ресурсов и без использования внутреннего подмножества.

Другими словами, когда вы используете

 $element->setAttribute('xml:id', 'test'); 

вам не нужно вызывать setIdAttribute , а также не указывать DTD или схему. DOM распознает атрибут xml:id при использовании с getElementById без необходимости проверки документа или чего-либо еще. Это подход с наименьшими усилиями. Обратите внимание, что в зависимости от вашей ОС и версии libxml вы не получите getElementById для работы вообще.

Решение проблемы2:

Даже если идентификаторы не будут извлекаемыми с помощью getElementById , вы все равно можете получить их с помощью XPath:

 $xpath->query('/pages/page[@id=1]'); 

определенно будет работать. Вы также можете напрямую загружать дочерние элементы продукта для конкретной страницы:

 $xpath->query('//pages/page[@id=1]/products'); 

Кроме того, вы можете сделать очень мало, чтобы код DOM выглядел менее подробным, потому что это действительно сложный интерфейс. Это должно быть, потому что DOM является языковым агностическим интерфейсом, который снова определяется W3C .


EDIT после комментария ниже

Он работает, как я объяснил выше. Вот полный тестовый пример для вас. Первая часть предназначена для написания новых файлов XML с DOM. Вот где вам нужно установить атрибут xml:id . Вы используете это вместо обычного атрибута id без имени.

 // Setup $dom = new DOMDocument; $dom->formatOutput = TRUE; $dom->preserveWhiteSpace = FALSE; $dom->loadXML('<pages/>'); // How to set a valid id attribute when not using a DTD or Schema $page1 = $dom->createElement('page'); $page1->setAttribute('xml:id', 'p1'); $page1->appendChild($dom->createElement('product', 'foo1')); $page1->appendChild($dom->createElement('product', 'foo2')); // How to set an ID attribute that requires a DTD or Schema when reloaded $page2 = $dom->createElement('page'); $page2->setAttribute('id', 'p2'); $page2->setIdAttribute('id', TRUE); $page2->appendChild($dom->createElement('product', 'bar1')); $page2->appendChild($dom->createElement('product', 'bar2')); // Appending pages and saving XML $dom->documentElement->appendChild($page1); $dom->documentElement->appendChild($page2); $xml = $dom->saveXML(); unset($dom, $page1, $page2); echo $xml; 

Это создаст XML-файл следующим образом:

 <?xml version="1.0"?> <pages> <page xml:id="p1"> <product>foo1</product> <product>foo2</product> </page> <page id="p2"> <product>bar1</product> <product>bar2</product> </page> </pages> 

Когда вы снова читаете в XML, новый экземпляр DOM больше не знает, что вы объявили атрибут id как атрибут идентификатора с атрибутом setIdAttribute . Он все равно будет в XML, но атрибут id будет просто регулярным атрибутом. Вы должны знать, что атрибуты идентификатора являются особыми в XML.

 // Load the XML we created above $dom = new DOMDocument; $dom->loadXML($xml); 

Теперь для некоторых тестов:

 echo "\n\n GETELEMENTBYID RETURNS ELEMENT WITH XML:ID \n\n"; foreach( $dom->getElementById('p1')->childNodes as $product) { echo $product->nodeValue; // Will output foo1 and foo2 with whitespace } 

Вышеописанное работает, поскольку синтаксический анализатор, совместимый с DOM, должен распознавать xml:id – это атрибут идентификатора, независимо от любого DTD или схемы. Это объясняется спецификациями, приведенными выше. Причина, по которой он выводит пробелы, заключается в том, что из-за форматированного вывода есть узлы DOMText между открывающим тегом, двумя тегами продукта и закрывающими тегами, поэтому мы повторяем пять узлов. Концепция узла имеет решающее значение для понимания при работе с XML.

 echo "\n\n GETELEMENTBYID CANNOT FETCH NORMAL ID \n\n"; foreach( $dom->getElementById('p2')->childNodes as $product) { echo $product->nodeValue; // Will output a NOTICE and a WARNING } 

Вышеуказанное не будет работать, потому что id не является атрибутом идентификатора. Чтобы анализатор DOM распознал его как таковой, вам нужно DTD или Schema, и XML должен быть проверен против него.

 echo "\n\n XPATH CAN FETCH NORMAL ID \n\n"; $xPath = new DOMXPath($dom); $page2 = $xPath->query('/pages/page[@id="p2"]')->item(0); foreach( $page2->childNodes as $product) { echo $product->nodeValue; // Will output bar1 and bar2 } 

XPath, с другой стороны, буквально об атрибутах, что означает, что вы можете запросить DOM для элемента страницы с id атрибута, если getElementById недоступен. Обратите внимание, что для запроса страницы с идентификатором p1 вам нужно будет включить пространство имен, например @xml:id="p1" .

 echo "\n\n XPATH CAN FETCH PRODUCTS FOR PAGE WITH ID \n\n"; $xPath = new DOMXPath($dom); foreach( $xPath->query('/pages/page[@id="p2"]/product') as $product ) { echo $product->nodeValue; // Will output bar1 and bar2 w\out whitespace } 

И, как сказано, вы также можете использовать XPath для запроса чего-либо еще в документе. Это не будет выводить пробелы, потому что оно будет возвращать только элементы product под страницей с id p2.

Вы также можете пересечь всю DOM с узла. Это древовидная структура. Поскольку DOMNode является самым важным классом в DOM, вы хотите ознакомиться с ним.

 echo "\n\n TRAVERSING UP AND DOWN \n\n"; $product = $dom->getElementsByTagName('product')->item(2); echo $product->tagName; // 'product' echo $dom->saveXML($product); // '<product>bar1</product>' // Going from bar1 to foo1 $product = $product->parentNode // Page Node ->parentNode // Pages Node ->childNodes->item(1) // Page p1 ->childNodes->item(1); // 1st Product echo $product->nodeValue; // 'foo1' // from foo1 to foo2 it is two(!) nodes because the XML is formatted echo $product->nextSibling->nodeName; // '#text' with whitespace and linebreak echo $product->nextSibling->nextSibling->nodeName; // 'product' echo $product->nextSibling->nextSibling->nodeValue; // 'foo2' 

На боковой панели, да, у меня есть опечатка в исходном коде выше. Это product не products . Но я считаю, что вряд ли можно утверждать, что код не работает, когда все, что вам нужно изменить, это s . Это просто слишком похоже на то, что ты хочешь быть ложкой.