【问题标题】:Using DOMXml and Xpath, to update XML entries使用 DOMXml 和 Xpath,更新 XML 条目
【发布时间】:2012-03-12 16:50:10
【问题描述】:

您好,我知道这里有很多关于将这三个主题组合在一起以更新 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 找到该节点然后更新它吗?

【问题讨论】:

标签: php xml dom xpath


【解决方案1】:

以下示例使用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

假设item元素中总是有一个category子元素,可以这样写:

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

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

$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,这个答案太多了。

【讨论】:

  • 哇,非常感谢你,我相信很多其他人会发现这非常有用!
猜你喜欢
  • 2011-09-01
  • 2015-11-06
  • 1970-01-01
  • 2011-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多