您好我知道这里有很多关于将这三个主题结合在一起更新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的节点然后更新它吗?
答案 0 :(得分:5)
以下示例正在使用simplexml
,它是DOMDocument
的密友。无论您使用哪种方法,显示的xpath都是相同的,我在这里使用simplexml
来保持低代码。我稍后会展示更高级的DOMDocument
示例。
关于xpath:如何找到节点并更新它。首先如何找到节点:
该节点具有元素/标记名item
。您正在storagehouse
元素中查找它,它是XML文档的根元素。文档中的所有item
元素在xpath中都表示如下:
/storagehouse/item
从根目录开始,先storagehouse
,然后item
。除以/
。您已经知道了,所以有趣的部分是如何只获取具有特定ID的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的项目)。如果有多个具有相同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
是该计算机监视器xml元素名称项的SimpleXMLElement
对象。
现在进行更改,在您的情况下使用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
假设category
元素中始终存在item
子元素,则可以这样写:
$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();
当然这需要more code,这对于这个答案来说太过分了。