28、XML 处理:从 XPath 查询到 DOM 操作的全面指南

XML 处理:从 XPath 查询到 DOM 操作的全面指南

1. XPath 查询基础

XPath 是一种强大的 XML 查询语言,能够帮助我们在 XML 文档中精准定位元素。例如,使用查询 “ /name” 可以匹配所有 <name> 元素,而不管它是包含在 <dog> 还是 <cat> 元素中。若要获取当前 SimpleXMLElement 的父元素,可以使用查询 “..” 或者 “parent:: “。

以下是一个简单的示例代码:

<?php
error_reporting(E_ALL);
$xml = simplexml_load_file("template.xhtml");
$content = $xml->xpath("//*[@id='main_center']");
print (String)$content[0];
?>

在这个例子中,我们使用查询 “//*[@id=’main_center’]” 来查找属性 id 等于 ‘main_center’ 的元素。在 XPath 中,使用 @ 符号来匹配属性。

2. XML 命名空间

XML 命名空间用于定义元素所属的集合,避免数据歧义。当存在不同类型的节点包含相同名称的元素时,命名空间就显得尤为重要。例如,我们可以为猫和狗定义不同的命名空间,确保它们的内部元素具有唯一的名称。

以下是一个使用命名空间的示例:

<?php
error_reporting(E_ALL ^ E_NOTICE);
$xml = <<<THE_XML
<animals xmlns:dog="http://foobar.com/dog" xmlns:cat="http://foobar.com/cat" >
  <dog:name>snoopy</dog:name>
  <dog:color>brown</dog:color>
  <dog:breed>beagle cross</dog:breed>
  <cat:name>teddy</cat:name>
  <cat:color>brown</cat:color>
  <cat:breed>tabby</cat:breed>
  <dog:name>jade</dog:name>
  <dog:color>black</dog:color>
  <dog:breed>lab cross</dog:breed>
</animals>
THE_XML;
$xml_object = simplexml_load_string($xml);
$xml_object->registerXPathNamespace('cat', 'http://foobar.com/cat');
$xml_object->registerXPathNamespace('dog', 'http://foobar.com/dog');
$names = $xml_object->xpath("dog:name");
foreach ($names as $name) {
    print $name . "<br/>";
}
?>

在运行 XPath 查询之前,我们需要先注册命名空间。注册后,在查询元素时需要为其添加命名空间前缀。

3. 根据元素值匹配元素并读取属性值

使用 XPath 的 contains 函数可以根据元素值匹配元素,然后读取该元素的属性值。

<?php
error_reporting(E_ALL);
$xml = <<<THE_XML
<animals>
  <dog>
    <name id="1">snoopy</name>
    <color>brown</color>
    <breed>beagle cross</breed>
  </dog>
  <cat>
    <name id="2">teddy</name>
    <color>brown</color>
    <breed>tabby</breed>
  </cat>
  <dog>
    <name id="3">jade</name>
    <color>black</color>
    <breed>lab cross</breed>
  </dog>
</animals>
THE_XML;
$xml_object = simplexml_load_string($xml);
$result = $xml_object->xpath("dog/name[contains(., 'jade')]");
print (String)$result[0]->attributes()->id;
?>

contains 函数接受两个参数,第一个参数表示搜索的位置( . 表示当前节点),第二个参数是搜索字符串。

4. RSS 解析

RSS(Really Simple Syndication)是一种用于发布和订阅内容的简单方法。以《连线》杂志的 RSS 订阅源为例,我们可以使用 XML 知识轻松解析其内容。

<table>
    <tr><th>Story</th><th>Date</th><th>Creator</th></tr>
<?php
error_reporting(E_ALL);
$xml = simplexml_load_file("http://feeds.wired.com/wired/index?format=xml");
foreach($xml->channel->item as $item){
    print "<tr><td><a href='".$item->link."'>".$item->title."</a></td>";
    print "<td>".$item->pubDate."</td>";
    $creator_by_xpath = $item->xpath("dc:creator");
    print "<td>".(String)$creator_by_xpath[0]."</td></tr>";
    //equivalent creator, using children function instead of xpath function
    //$creator_by_namespace = $item->children('http://purl.org/dc/elements/1.1/')->creator;
    //print "<td>".(String)$creator_by_namespace[0]."</td></tr>";
}
?>
</table>

在这个示例中,我们创建了一个包含文章标题、发布日期和创作者的表格。注意,在 XML 中,创作者元素位于命名空间中,因此我们使用 XPath 来获取它。

5. 使用 SimpleXML 生成 XML 文档

我们可以使用 SimpleXML 从数组、对象或数据库等数据形式生成 XML 文档。以下是一个基本的示例:

<?php
error_reporting(E_ALL ^ E_NOTICE);
//generate the xml, starting with the root
$animals = new SimpleXMLElement('<animals/>');
$animals->{0} = 'Hello World';
$animals->asXML('animals.xml');
//verify no errors with our newly created output file
var_dump(simplexml_load_file('animals.xml'));
?>

这个示例创建了一个根元素 <animals> ,并为其赋值,然后将其保存到文件中。为了验证操作是否成功,我们加载保存的文件并输出其内容。

6. 从数组数据生成 XML 文档

当我们有动物数据以数组形式存储时,可以使用 SimpleXML 将其转换为 XML 文档。

<?php
error_reporting(E_ALL ^ E_NOTICE);
//our data, stored in arrays
$dogs_array = array(
    array("name" => "snoopy",
        "color" => "brown",
        "breed" => "beagle cross"
    ),
    array("name" => "jade",
        "color" => "black",
        "breed" => "lab cross"
    ),
);
$cats_array = array(
    array("name" => "teddy",
        "color" => "brown",
        "breed" => "tabby"
    ),
);
//generate the xml, starting with the root
$animals = new SimpleXMLElement('<animals/>');
$cats_xml = $animals->addChild('cats');
$dogs_xml = $animals->addChild('dogs');
foreach ($cats_array as $c) {
    $cat = $cats_xml->addChild('cat');
    foreach ($c as $key => $value) {
        $tmp = $cat->addChild($key);
        $tmp->{0} = $value;
    }
}
foreach ($dogs_array as $d) {
    $dog = $dogs_xml->addChild('dog');
    foreach ($d as $key => $value) {
        $tmp = $dog->addChild($key);
        $tmp->{0} = $value;
    }
}
var_dump($animals);
$animals->asXML('animals.xml');
print '<br/><br/>';
//verify no errors with our newly created output file
var_dump(simplexml_load_file('animals.xml'));
?>

通过不断调用 addChild 方法,我们可以创建一个完整的节点树。不过, asXML() 方法输出的内容格式不太美观,我们可以使用 DOMDocument 类来解决这个问题。

graph TD;
    A[开始] --> B[创建 SimpleXMLElement 根元素];
    B --> C[添加子元素];
    C --> D[保存为 XML 文件];
    D --> E[验证文件是否正确];
    E --> F[结束];
7. 使用 DOMDocument 格式化 XML 输出

为了让 XML 输出格式更美观,我们可以使用 DOMDocument 类。

$animals_dom = new DOMDocument('1.0');
$animals_dom->preserveWhiteSpace = false;
$animals_dom->formatOutput = true;
//returns a DOMElement
$animals_dom_xml = dom_import_simplexml($animals);
$animals_dom_xml = $animals_dom->importNode($animals_dom_xml, true);
$animals_dom_xml = $animals_dom->appendChild($animals_dom_xml);
$animals_dom->save('animals_formatted.xml');

这段代码创建了一个新的 DOMDocument 对象,并设置其格式化输出。然后将 SimpleXMLElement 对象导入到新的 DOMElement 对象中,最后将格式化后的输出保存到文件中。

8. DOMDocument 概述

除了 SimpleXML DOMDocument 也是 PHP 中常用的 XML 处理扩展。它比 SimpleXML 更强大,但使用起来相对复杂一些。 DOMDocument 具有以下特点:
- 遵循 W3C DOM API,熟悉 JavaScript DOM 的开发者容易上手。
- 支持 HTML 解析。
- 具有不同的节点类型,提供更多的控制。
- 可以将原始 XML 追加到现有 XML 文档中。
- 更易于通过更新或删除节点来修改现有文档。
- 对 CDATA 和注释提供更好的支持。

9. DOMDocument 的使用

DOMDocument 可以从字符串、文件或 SimpleXML 对象加载 XML。

//creating a DOMDocument object
$dom_xml = new DOMDocument();
//from a string
$dom_xml->loadXML('the full xml string');
// from a file
$dom_xml->load('animals.xml');
// imported from a SimpleXML object
$dom_element = dom_import_simplexml($simplexml);
$dom_element = $dom_xml->importNode($dom_element, true);
$dom_element = $dom_xml->appendChild($dom_element);

要在 DOM 对象中导航,可以使用面向对象的函数调用,如 $dom_xml->item(0)->firstChild->nodeValue $dom_xml->childNodes 等。此外, DOMDocument 还提供了多个保存函数,如 save saveHTML saveHTMLFile saveXML ,以及 validate 函数来检查文档的合法性。

10. 使用 DOM 进行元素查找和属性值搜索

以下是使用 DOM 进行元素查找和属性值搜索的示例:

<?php
error_reporting(E_ALL ^ E_NOTICE);
$xml = <<<THE_XML
<animals>
  <dog>
    <name>snoopy</name>
    <color>brown</color>
    <breed>beagle cross</breed>
  </dog>
  <cat>
    <name>teddy</name>
    <color>brown</color>
    <breed>tabby</breed>
  </cat>
  <dog>
    <name>jade</name>
    <color>black</color>
    <breed>lab cross</breed>
  </dog>
</animals>
THE_XML;
$xml_object = new DOMDocument();
$xml_object->loadXML($xml);
$xpath = new DOMXPath($xml_object);
$names = $xpath->query("*/name");
foreach ($names as $element) {
    $parent_type = $element->parentNode->nodeName;
    echo "$element->nodeValue ($parent_type)<br/>";
}
?>
<?php
error_reporting(E_ALL);
$xml = <<<THE_XML
<animals>
  <dog>
    <name id="1">snoopy</name>
    <color>brown</color>
    <breed>beagle cross</breed>
  </dog>
  <cat>
    <name id="2">teddy</name>
    <color>brown</color>
    <breed>tabby</breed>
  </cat>
  <dog>
    <name id="3">jade</name>
    <color>black</color>
    <breed>lab cross</breed>
  </dog>
</animals>
THE_XML;
$xml_object = new DOMDocument();
$xml_object->loadXML($xml);
$xpath = new DOMXPath($xml_object);
// 后续代码可根据具体需求补充
?>

在这些示例中,我们展示了如何使用 DOM 进行元素查找和属性值搜索。与 SimpleXML 不同, DOM 需要创建 DOMXPath 对象并调用其 query 方法。

通过以上内容,我们全面介绍了 XML 处理的各个方面,包括 XPath 查询、命名空间使用、RSS 解析、 SimpleXML 生成 XML 文档以及 DOMDocument 的使用等。希望这些知识能帮助你更好地处理 XML 数据。

XML 处理:从 XPath 查询到 DOM 操作的全面指南

11. DOMDocument 与 SimpleXML 的对比

为了更清晰地展示 DOMDocument SimpleXML 的差异,我们来详细对比一下它们的特点和使用场景。

特性 SimpleXML DOMDocument
易用性 简单直接,适合快速开发和简单的 XML 处理任务 相对复杂,需要更多的代码和步骤,但功能更强大
节点类型 所有节点使用相同的底层对象,缺乏明确的节点类型区分 具有不同的节点类型,如 XML_ELEMENT_NODE XML_ATTRIBUTE_NODE XML_TEXT_NODE ,提供更精细的控制
输出格式化 asXML() 方法输出的内容格式不美观,通常为单行 可以通过设置 preserveWhiteSpace formatOutput 属性来实现漂亮的格式化输出
遵循标准 无特定标准遵循 遵循 W3C DOM API,对于熟悉 JavaScript DOM 的开发者更友好
功能扩展性 功能相对有限,主要用于基本的 XML 解析和生成 支持 HTML 解析、追加原始 XML、修改现有文档等更多高级功能
12. 处理 XML 文档中的命名空间(DOMDocument 方式)

在使用 DOMDocument 处理包含命名空间的 XML 文档时,我们需要进行一些额外的操作。以下是一个示例:

<?php
error_reporting(E_ALL ^ E_NOTICE);
$xml = <<<THE_XML
<animals xmlns:dog="http://foobar.com/dog" xmlns:cat="http://foobar.com/cat" >
  <dog:name>snoopy</dog:name>
  <dog:color>brown</dog:color>
  <dog:breed>beagle cross</dog:breed>
  <cat:name>teddy</cat:name>
  <cat:color>brown</cat:color>
  <cat:breed>tabby</cat:breed>
  <dog:name>jade</dog:name>
  <dog:color>black</dog:color>
  <dog:breed>lab cross</dog:breed>
</animals>
THE_XML;
$dom_xml = new DOMDocument();
$dom_xml->loadXML($xml);
$xpath = new DOMXPath($dom_xml);
$xpath->registerNamespace('dog', 'http://foobar.com/dog');
$xpath->registerNamespace('cat', 'http://foobar.com/cat');
$names = $xpath->query('dog:name');
foreach ($names as $name) {
    echo $name->textContent . '<br/>';
}
?>

在这个示例中,我们首先创建了一个 DOMDocument 对象并加载 XML 字符串。然后,我们创建了一个 DOMXPath 对象,并使用 registerNamespace 方法注册命名空间。最后,我们使用 query 方法执行 XPath 查询,并遍历结果输出狗的名字。

13. 修改现有 XML 文档(DOMDocument 方式)

DOMDocument 提供了强大的功能来修改现有 XML 文档。以下是一个示例,展示如何更新节点的值和删除节点:

<?php
error_reporting(E_ALL);
$xml = <<<THE_XML
<animals>
  <dog>
    <name id="1">snoopy</name>
    <color>brown</color>
    <breed>beagle cross</breed>
  </dog>
  <cat>
    <name id="2">teddy</name>
    <color>brown</color>
    <breed>tabby</breed>
  </cat>
  <dog>
    <name id="3">jade</name>
    <color>black</color>
    <breed>lab cross</breed>
  </dog>
</animals>
THE_XML;
$dom_xml = new DOMDocument();
$dom_xml->loadXML($xml);
// 更新节点的值
$name_nodes = $dom_xml->getElementsByTagName('name');
foreach ($name_nodes as $name_node) {
    if ($name_node->textContent == 'snoopy') {
        $name_node->textContent = 'Snoopy the Hero';
    }
}
// 删除节点
$cat_node = $dom_xml->getElementsByTagName('cat')->item(0);
if ($cat_node) {
    $cat_node->parentNode->removeChild($cat_node);
}
// 保存修改后的 XML
$dom_xml->save('modified_animals.xml');
?>

在这个示例中,我们首先加载 XML 字符串到 DOMDocument 对象中。然后,我们使用 getElementsByTagName 方法获取所有 <name> 节点,并更新名为 ‘snoopy’ 的节点的值。接着,我们删除了第一个 <cat> 节点。最后,我们使用 save 方法将修改后的 XML 保存到文件中。

14. 处理 XML 文档中的 CDATA 和注释(DOMDocument 方式)

DOMDocument 对 CDATA 和注释提供了很好的支持。以下是一个示例:

<?php
error_reporting(E_ALL ^ E_NOTICE);
$dom_xml = new DOMDocument();
$root = $dom_xml->createElement('root');
$dom_xml->appendChild($root);
// 添加 CDATA 节点
$cdata = $dom_xml->createCDATASection('This is a CDATA section with special characters <>&');
$root->appendChild($cdata);
// 添加注释节点
$comment = $dom_xml->createComment('This is a comment');
$root->appendChild($comment);
// 保存 XML
$dom_xml->save('cdata_comment.xml');
?>

在这个示例中,我们创建了一个 DOMDocument 对象,并添加了一个根元素。然后,我们使用 createCDATASection 方法创建了一个 CDATA 节点,并使用 createComment 方法创建了一个注释节点。最后,我们将这些节点添加到根元素中,并将 XML 保存到文件中。

15. 总结与最佳实践

通过以上对 XML 处理的各个方面的介绍,我们可以总结出一些最佳实践:
- 简单任务优先选择 SimpleXML :如果你的 XML 处理任务比较简单,如快速解析或生成基本的 XML 文档, SimpleXML 是一个不错的选择,它的代码简洁,易于上手。
- 复杂任务使用 DOMDocument :对于需要处理复杂 XML 结构、进行精细控制、修改现有文档或处理命名空间等高级任务, DOMDocument 更适合,虽然它的使用相对复杂,但功能强大。
- 合理使用 XPath :XPath 是 XML 查询的强大工具,无论是 SimpleXML 还是 DOMDocument 都支持 XPath 查询。在编写 XPath 查询时,要注意命名空间的处理,确保查询的准确性。
- 注意输出格式化 :如果需要美观的 XML 输出,使用 DOMDocument formatOutput 属性进行格式化。
- 错误处理 :在处理 XML 时,要注意错误处理,确保代码的健壮性。可以使用 error_reporting 函数来控制错误信息的显示。

graph LR;
    A[选择处理方式] -->|简单任务| B[SimpleXML];
    A -->|复杂任务| C[DOMDocument];
    B --> D[快速解析/生成 XML];
    C --> E[处理命名空间];
    C --> F[修改现有文档];
    C --> G[处理 CDATA 和注释];
    D --> H[完成任务];
    E --> H;
    F --> H;
    G --> H;

通过遵循这些最佳实践,你可以更高效地处理 XML 数据,避免常见的错误和问题。希望这些内容对你在 XML 处理方面有所帮助,让你能够更加熟练地运用相关技术来解决实际问题。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值