Использование DOMXml и Xpath для обновления записей XML - PullRequest
2 голосов
/ 12 марта 2012

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

Я потратил некоторое время, пытаясь понять XPath и его пути, но я все еще не могу понять, что мне нужно делать.

Вот и мы

У меня есть этот XML-файл

 <?xml version="1.0" encoding="UTF-8"?>
<storagehouse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:noNamespaceSchemaLocation="schema.xsd">
    <item id="c7278e33ef0f4aff88da10dfeeaaae7a">
        <name>HDMI Cable 3m</name>
        <weight>0.5</weight>
        <category>Cables</category>
        <location>B3</location>
    </item>
    <item id="df799fb47bc1e13f3e1c8b04ebd16a96">
        <name>Dell U2410</name>
        <weight>2.5</weight>
        <category>Monitors</category>
        <location>C2</location>
    </item>
    </storagehouse>

Что я хотел бы сделать, это обновить / отредактировать любой из указанных выше узлов, когда мне это нужно. Я сделаю HTML-форму для этого. Но моя самая большая проблема в том, как найти и обновить нужный узел и обновить его?

Здесь у меня есть кое-что из того, что я пытаюсь сделать

<?php

 function fnDOMEditElementCond()
   {
       $dom = new DOMDocument();
       $dom->load('storage.xml');
       $library = $dom->documentElement;
       $xpath = new DOMXPath($dom);
      // I kind of understand this one here
       $result = $xpath->query('/storagehouse/item[1]/name');
       //This one not so much
       $result->item(0)->nodeValue .= ' Series';
       // This will remove the CDATA property of the element.
       //To retain it, delete this element (see delete eg) & recreate it with CDATA (see create xml eg).

       //2nd Way
       //$result = $xpath->query('/library/book[author="J.R.R.Tolkein"]');
      // $result->item(0)->getElementsByTagName('title')->item(0)->nodeValue .= ' Series';
       header("Content-type: text/xml");
       echo $dom->saveXML();


   }
?>

Может ли кто-нибудь дать мне примеры с атрибутами и так далее, чтобы один пользователь решил обновить нужный узел, я мог бы найти этот узел с помощью XPath и затем обновить его?

1 Ответ

5 голосов
/ 12 марта 2012

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

Итак, о xpath: как найти узел и обновить его. Прежде всего, как найти узел:

Узел имеет элемент / тэг item. Вы ищете его внутри элемента storagehouse, который является корневым элементом вашего XML-документа. Все элементы item в вашем документе выражаются следующим образом в xpath:

/storagehouse/item

Из корня сначала storagehouse, затем item. Разделено с /. Вы уже знаете это, поэтому интересная часть состоит в том, как взять только те элементы item, которые имеют определенный идентификатор. Для этого предикат используется и добавляется в конце:

/storagehouse/item[@id="id"]

Это вернет все элементы item снова, но на этот раз только те, которые имеют атрибут id со значением id (строка). Например, в вашем случае со следующим XML:

$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<storagehouse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="schema.xsd">
    <item id="c7278e33ef0f4aff88da10dfeeaaae7a">
        <name>HDMI Cable 3m</name>
        <weight>0.5</weight>
        <category>Cables</category>
        <location>B3</location>
    </item>
    <item id="df799fb47bc1e13f3e1c8b04ebd16a96">
        <name>Dell U2410</name>
        <weight>2.5</weight>
        <category>Monitors</category>
        <location>C2</location>
    </item>
</storagehouse>
XML;

тот xpath:

/storagehouse/item[@id="df799fb47bc1e13f3e1c8b04ebd16a96"]

вернет монитор компьютера (поскольку такой элемент с таким идентификатором существует). Если будет несколько элементов с одинаковым значением id, будет возвращено несколько элементов. Если бы их не было, ни один не был бы возвращен. Итак, давайте свернем это в пример кода:

$simplexml = simplexml_load_string($xml);
$result = $simplexml->xpath(sprintf('/storagehouse/item[@id="%s"]', $id));
if (!$result || count($result) !== 1) {
    throw new Exception(sprintf('Item with id "%s" does not exists or is not unique.', $id));
}
list($item) = $result;

В этом примере $titem - это объект SimpleXMLElement этого элемента имени xml-элемента монитора компьютера.

Так что теперь об изменениях, которые чрезвычайно просты с SimpleXML в вашем случае:

$item->category = 'LCD Monitor';

И чтобы наконец увидеть результат:

echo $simplexml->asXML();

Да, это все с SimpleXML в вашем случае.

Если вы хотите сделать это с DOMDocument, он работает очень похоже. Однако для обновления значения элемента вам также необходим доступ к дочернему элементу этого элемента. Давайте посмотрим на следующий пример, который в первую очередь также получает элемент. Если вы сравните с примером SimpleXML, приведенным выше, вы увидите, что на самом деле вещи не отличаются:

$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
$result = $xpath->query(sprintf('/storagehouse/item[@id="%s"]', $id));
if (!$result || $result->length !== 1) {
    throw new Exception(sprintf('Item with id "%s" does not exists or is not unique.', $id));
}
$item = $result->item(0);

Опять же, $item содержит элемент XML элемента монитора компьютера. Но на этот раз как DOMElement. Чтобы изменить там элемент category (или, точнее, nodeValue), сначала нужно получить дочерние элементы. Вы можете сделать это снова с xpath, но на этот раз с выражением относительно элемента $item:

./category

Предполагая, что в элементе item всегда есть дочерний элемент category, это можно записать так:

$category = $xpath->query('./category', $item)->item(0);

$category теперь содержит первый category дочерний элемент $item. Осталось обновить его значение:

$category->nodeValue = "LCD Monitor";

И, наконец, увидеть результат:

echo $doc->saveXML();

И это все. Выбираете ли вы SimpleXML или DOMDocument, это зависит от ваших потребностей. Вы даже можете переключаться между ними. Возможно, вы захотите сопоставить и проверить изменения:

$repository = new Repository($xml);
$item = $repository->getItemByID($id);
$item->category = 'LCD Monitor';
$repository->saveChanges();
echo $repository->getXML();

Естественно, для этого требуется больше кода , что слишком много для этого ответа.

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