В следующем примере используется 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();
Естественно, для этого требуется больше кода , что слишком много для этого ответа.