使用DOMXml和Xpath来更新XML条目

Eir*_*man 2 php xml xpath dom

您好我知道这里有很多关于这三个主题组合起来更新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>
Run Code Online (Sandbox Code Playgroud)

我想要做的是在需要时更新/编辑上面的任何节点.我会为此做一个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();


   }
?>
Run Code Online (Sandbox Code Playgroud)

有人可能会给我一个带属性等的例子,所以一个用户决定更新一个所需的节点,我可以用XPath找到该节点,然后更新它?

hak*_*kre 5

以下示例正在利用simplexml其中的密友DOMDocument.无论使用哪种方法,显示的xpath都是相同的,我simplexml在这里用来保持低代码.我稍后会展示一个更高级的DOMDocument例子.

关于xpath:如何找到节点并更新它.首先如何找到节点:

该节点具有元素/标记名item.您正在storagehouse元素中查找它,元素是XML文档的根元素.item文档中的所有元素都在xpath中表示如下:

/storagehouse/item
Run Code Online (Sandbox Code Playgroud)

从根,首先storagehouse,然后item.除以/.你已经知道了,所以有趣的部分是如何只采用那些item具有特定ID的元素.为此,使用谓词并在末尾添加:

/storagehouse/item[@id="id"]
Run Code Online (Sandbox Code Playgroud)

这将item再次返回所有元素,但这次只有那些具有idid(字符串)属性的元素.例如,在您的情况下使用以下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;
Run Code Online (Sandbox Code Playgroud)

那个xpath:

/storagehouse/item[@id="df799fb47bc1e13f3e1c8b04ebd16a96"]
Run Code Online (Sandbox Code Playgroud)

将返回计算机监视器(因为存在具有该id的项目).如果有多个具有相同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;
Run Code Online (Sandbox Code Playgroud)

在此示例中,$titem是该SimpleXMLElement计算机监视器xml元素名称项的对象.

所以现在进行更改,SimpleXML在您的情况下非常容易:

$item->category = 'LCD Monitor';
Run Code Online (Sandbox Code Playgroud)

最后看到结果:

echo $simplexml->asXML();
Run Code Online (Sandbox Code Playgroud)

是的,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);
Run Code Online (Sandbox Code Playgroud)

同样,$item包含计算机监视器的项XML元素.但这次作为一个DOMElement.要修改category那里的元素(或者更确切地说是它nodeValue),需要首先获得子元素.您可以使用xpath再次执行此操作,但这次使用相对于$item元素的表达式:

./category
Run Code Online (Sandbox Code Playgroud)

假设category元素中始终存在子item元素,则可以这样写:

$category = $xpath->query('./category', $item)->item(0);
Run Code Online (Sandbox Code Playgroud)

$category现在包含第一category个子元素$item.剩下的就是更新它的价值:

$category->nodeValue = "LCD Monitor";
Run Code Online (Sandbox Code Playgroud)

最后看到结果:

echo $doc->saveXML();
Run Code Online (Sandbox Code Playgroud)

就是这样.无论您选择SimpleXML还是DOMDocument,都取决于您的需求.你甚至可以在两者之间切换.您可能想要映射并检查更改:

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

当然,这需要更多的代码,这对于这个答案来说太过分了.