搜索
首页php教程php手册PHP的XML分析函数(转) (介绍这个PHP里的XML分析函数的文章可不太有哦。。 看过这篇就应该清楚点了吧...

xml|函数

PHP的XML分析函数

首先我得承认我喜欢计算机标准。如果每个人都遵从这个行业的标准,互联网将会是一个更好的媒体。使用标准化的数据交换格式才能使开放的和独立于平台的计算模式切实可行。这就是我作为XML爱好者的原因。

幸运的是,我最喜爱的脚本语言不但支持XML而且对其支持正不断加强。PHP可以让我迅速将XML文档发布到互联网上,收集XML文档的统计信息,将XML文档转换成其它格式。例如,我时常用PHP的XML处理能力来管理我用XML所写的文章和书。

本文中,我将讨论任何用PHP内建的Expat解析器来处理XML文档。通过范例,我将演示Expat的处理方法。同时,范例可以告诉你如何:

建立你自己的处理函数  
将XML文档转换成你自己的PHP数据结构

介绍Expat

XML的解析器,同样称为XML处理器,可以使程序访问XML文档的结构和内容。Expat是PHP脚本语言的XML解析器。它同时也运用在其它项目中,例如Mozilla、Apache和Perl。

什么是基于事件的解析器?

XML解析器的两种基本类型:

基于树型的解析器:将XML文档转换成树型结构。这类解析器分析整篇文章,同时提供一个API来访问所产生树的每个元素。其通用的标准为DOM(文档对象模式)。  
基于事件的解析器:将XML文档视为一系列的事件。当一个特殊事件发生时,解析器将调用开发者提供的函数来处理。  
基于事件的解析器有一个XML文档的数据集中视图,也就是说它集中在XML文档的数据部分,而不是其结构。这些解析器从头到尾处理文档,并将类似于-元素的开始、元素的结尾、特征数据的开始等等-事件通过回调(callback)函数报告给应用程序。以下是一个"Hello-World"的XML文档范例:

  
Hello World  
  

基于事件的解析器将报告为三个事件:

开始元素:greeting  
CDATA项的开始,值为:Hello World  
结束元素:greeting  
不像基于树型的解析器,基于事件的解析器不产生描述文档的结构。在CDATA项中,基于事件的解析器不会让你得到父元素greeting的信息。
然而,它提供一个更底层的访问,这就使得可以更好地利用资源和更快地访问。通过这种方式,就没有必要将整个文档放入内存;而事实上,整个文档甚至可以大于实际内存值。


Expat就是这样的一种基于事件的解析器。当然如果使用Expat,必要时它一样可以在PHP中生成完全的原生树结构。


上面Hello-World的范例包括完整的XML格式。但它是无效的,因为既没有DTD(文档类型定义)与其联系,也没有内嵌DTD。


对于Expat,这并没有区别:Expat是一个不检查有效性的解析器,因此忽略任何与文档联系的DTD。但应注意的是文档仍然需要完整的格式,否则Expat(和其他符合XML标准的解析器一样)将会随着出错信息而停止。


作为不检查有效性的解析器,Exapt的快速性和轻巧性使其十分适合互联网程序。


编译Expat

Expat可以编译进PHP3.0.6版本(或以上)中。从Apache1.3.9开始,Expat已经作为Apache的一部分。在Unix系统中,通过-with-xml选项配置PHP,你可以将其编译入PHP。


如果你将PHP编译为Apache的模块,而Expat将默认作为Apache的一部分。在Windows中,你则必须要加载XML动态连接库。

XML范例:XMLstats

了解Expat的函数的一个办法就是通过范例。我们所要讨论的范例是使用Expat来收集XML文档的统计数据。


对于文档中每个元素,以下信息都将被输出:

该元素在文档中使用的次数  
该元素中字符数据的数量  
元素的父元素  
元素的子元素  
注意:为了演示,我们利用PHP来产生一个结构来保存元素的父元素和子元素

准备

用于产生XML解析器实例的函数为xml_parser_create()。该实例将用于以后的所有函数。这个思路非常类似于PHP中MySQL函数的连接标记。在解析文档前,基于事件的解析器通常要求你注册回调函数-用于特定的事件发生时调用。Expat没有例外事件,它定义了如下七个可能事件:


对象 XML解析函数 描述

元素 xml_set_element_handler() 元素的开始和结束

字符数据 xml_set_character_data_handler() 字符数据的开始

外部实体 xml_set_external_entity_ref_handler() 外部实体出现

未解析外部实体 xml_set_unparsed_entity_decl_handler() 未解析的外部实体出现

处理指令 xml_set_processing_instruction_handler() 处理指令的出现

记法声明 xml_set_notation_decl_handler() 记法声明的出现

默认 xml_set_default_handler() 其它没有指定处理函数的事件

所有的回调函数必须将解析器的实例作为其第一个参数(此外还有其它参数)。


对于本文最后的范例脚本。你需要注意的是它既用到了元素处理函数又用到了字符数据处理函数。元素的回调处理函数通过xml_set_element_handler()来注册。


这个函数需要三个参数:

解析器的实例  
处理开始元素的回调函数的名称  
处理结束元素的回调函数的名称  
当开始解析XML文档时,回调函数必须存在。它们必须定义为与PHP手册中所描述的原型一致。


例如,Expat将三个参数传递给开始元素的处理函数。在脚本范例中,其定义如下:


function start_element($parser, $name, $attrs)  


第一个参数是解析器标示,第二个参数是开始元素的名称,第三参数为包含元素所有属性和值的数组。


一旦你开始解析XML文档,Expat在遇到开始元素是都将调用你的start_element()函数并将参数传递过去。


XML的Case Folding选项

用xml_parser_set_option()函数将Case folding选项关闭。这个选项默认是打开的,使得传递给处理函数的元素名自动转换为大写。但XML对大小写是敏感的(所以大小写对统计XML文档是非常重要的)。对于我们的范例,case folding选项必须关闭。


解析文档

在完成所有的准备工作后,现在脚本终于可以解析XML文档:

Xml_parse_from_file(),一个自定义的函数,打开参数中指定的文件,并以4kb的大小进行解析  
xml_parse()和xml_parse_from_file()一样,当发生错误时,即XML文档的格式不完全时,将会返回false。  
你可以使用xml_get_error_code()函数来得到最后一个错误的数字代码。将此数字代码传递给xml_error_string()函数即可得到错误的文本信息。  
输出XML当前的行数,使得调试更容易。  
在解析的过程中,调用回调函数。  
描述文档结构

当解析文档时,对于Expat需要强调问题的是:如何保持文档结构的基本描述?


如前所述,基于事件的解析器本身并不产生任何结构信息。


不过标签(tag)结构是XML的重要特性。例如,元素序列表示的意思不同于<figure><title>。也就是说,任何作者都会告诉你书名和图名是没有关系的,虽然它们都用到"title"这个术语。因此,为了更有效地使用基于事件的解析器处理XML,你必须使用自己的栈(stacks)或列表(lists)来维护文档的结构信息。 <br><br><br>为了产生文档结构的镜像,脚本至少需要知道目前元素的父元素。用Exapt的API是无法实现的,它只报告目前元素的事件,而没有任何前后关系的信息。因此,你需要建立自己的栈结构。 <br><br><br>脚本范例使用先进后出(FILO)的栈结构。通过一个数组,栈将保存全部的开始元素。对于开始元素处理函数,目前的元素将被array_push()函数推到栈的顶部。相应的,结束元素处理函数通过array_pop()将最顶的元素移走。 <br><br><br>对于序列<book><title>,栈的填充如下:

开始元素book:将"book"赋给栈的第一个元素($stack[0])。  
开始元素title:将"title"赋给栈的顶部($stack[1])。  
结束元素title:从栈中将最顶部的元素移去($stack[1])。  
结束元素title:从栈中将最顶部的元素移去($stack[0])。  
PHP3.0通过一个$depth变量手动控制元素的嵌套来实现范例。这就使脚本看起来比较复杂。PHP4.0通过array_pop()和array_push()两个函数来使脚本看起来更简洁。


收集数据

为了收集每个元素的信息,脚本需要记住每个元素的事件。通过使用一个全局的数组变量$elements来保存文档中所有不同的元素。数组的项目是元素类的实例,有4个属性(类的变量)

$count -该元素在文档中被发现的次数  
$chars -元素中字符事件的字节数  
$parents -父元素  
$childs - 子元素  
正如你所看到的,将类实例保存在数组中是轻而易举的。


注意:PHP的一个特性是你可以通过while(list() = each())loop遍历整个类结构,如同你遍历整个相应的数组一样。所有的类变量(当你用PHP3.0时还有方法名)都以字符串的方式输出。


当发现一个元素时,我们需要增加其相应的记数器来跟踪它在文档中出现多少次。在相应的$elements项中的记数元素也要加一。


我们同样要让父元素知道目前的元素是它的子元素。因此,目前元素的名称将会加入到父元素的$childs数组的项目中。最后,目前元素应该记住谁是它的父元素。所以,父元素被加入到目前元素$parents数组的项目中。


显示统计信息

剩下的代码在$elements数组和其子数组中循环显示其统计结果。这就是最简单的嵌套循环,尽管输出正确的结果,但代码既不简洁又没有任何特别的技巧,它仅仅是一个你可能每天用他来完成工作的循环。


脚本范例被设计为通过PHP的CGI方式的命令行来调用。因此,统计结果输出的格式为文本格式。如果你要将脚本运用到互联网上,那么你需要修改输出函数来产生HTML格式。

总结

Exapt是PHP的XML解析器。作为基于事件的解析器,它不产生文档的结构描述。但通过提供底层访问,这就使得可以更好地利用资源和更快地访问。


作为一个不检查有效性的解析器,Expat忽略与XML文档连接的DTD,但如果文档的格式不完整,它将会随着出错信息而停止。


提供事件处理函数来处理文档  
建立自己的事件结构例如栈和树来获得XML结构信息标记的优点。  
每天都有新的XML程序出现,而PHP对XML的支持也不断加强(例如,增加了支持基于DOM的XML解析器LibXML)。


有了PHP和Expat,你就可以为即将出现的有效、开放和独立于平台的标准作准备。

范例

  
/*****************************************************************************  
* 名称:XML解析范例:XML文档信息统计
* 描述  
* 本范例通过PHP的Expat解析器收集和统计XML文档的信息(例如:每个元素出现的次数、父元素和子元素  
* XML文件作为一个参数 ./xmlstats_PHP4.php3 test.xml  
* $Requires: Expat 要求:Expat PHP4.0编译为CGI模式  
*****************************************************************************/  

// 第一个参数是XML文件
$file = $argv[1];  

// 变量的初始化
$elements = $stack = array();  
$total_elements = $total_chars = 0;  

// 元素的基本类
class element  
{  
var $count = 0;  
var $chars = 0;  
var $parents = array();  
var $childs = array();  
}  

// 解析XML文件的函数
function xml_parse_from_file($parser, $file)  
{  
if(!file_exists($file))  
{  
die("Can't find file \"$file\".");  
}  

if(!($fp = @fopen($file, "r")))  
{  
die("Can't open file \"$file\".");  
}  

while($data = fread($fp, 4096))  
{  
if(!xml_parse($parser, $data, feof($fp)))  
{  
return(false);  
}  
}  

fclose($fp);  

return(true);  
}  

// 输出结果函数(方框形式)
function print_box($title, $value)  
{  
printf("\n+%'-60s+\n", "");  
printf("|%20s", "$title:");  
printf("%14s", $value);  
printf("%26s|\n", "");  
printf("+%'-60s+\n", "");  
}  

// 输出结果函数(行形式)
function print_line($title, $value)  
{  
printf("%20s", "$title:");  
printf("%15s\n", $value);  
}  

// 排序函数
function my_sort($a, $b)  
{  
return(is_object($a) && is_object($b) ? $b->count - $a->count: 0);  
}  

function start_element($parser, $name, $attrs)  
{  
global $elements, $stack;  

// 元素是否已在全局$elements数组中?
if(!isset($elements[$name]))  
{  
// 否-增加一个元素的类实例
$element = new element;  
$elements[$name] = $element;  
}  

// 该元素的记数器加一
$elements[$name]->count++;  

// 是否有父元素?
if(isset($stack[count($stack)-1]))  
{  
// 是-将父元素赋给$last_element
$last_element = $stack[count($stack)-1];  

// 如果目前元素的父元素数组为空,初始化为0
if(!isset($elements[$name]->parents[$last_element]))  
{  
$elements[$name]->parents[$last_element] = 0;  
}  

// 该元素的父元素记数器加一
$elements[$name]->parents[$last_element]++;  

// 如果目前元素的父元素的子元素数组为空,初始化为0

if(!isset($elements[$last_element]->childs[$name]))  
{  
$elements[$last_element]->childs[$name] = 0;  
}  

// 该元素的父元素的子元素记数器加一
$elements[$last_element]->childs[$name]++;  
}  

// 将目前的元素加入到栈中
array_push($stack, $name);  
}  

function stop_element($parser, $name)  
{  
global $stack;  

// 从栈中将最顶部的元素移去
array_pop($stack);  
}  

function char_data($parser, $data)  
{  
global $elements, $stack, $depth;  

// 增加目前元素的字符数目
$elements[$stack][count($stack)-1]]->chars += strlen(trim($data));  
}  

// 产生解析器的实例
$parser = xml_parser_create();  

// 设置处理函数
xml_set_element_handler($parser, "start_element", "stop_element");  
xml_set_character_data_handler($parser, "char_data");  
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);  

// 解析文件
$ret = xml_parse_from_file($parser, $file);  
if(!$ret)  
{  
die(sprintf("XML error: %s at line %d",  
xml_error_string(xml_get_error_code($parser)),  
xml_get_current_line_number($parser)));  
}  

// 释放解析器
xml_parser_free($parser);  

// 释放协助元素
unset($elements["current_element"]);  
unset($elements["last_element"]);  

// 根据元素的次数排序
uasort($elements, "my_sort");  

// 在$elements中循环收集元素信息
while(list($name, $element) = each($elements))  
{  
print_box("Element name", $name);  

print_line("Element count", $element->count);  
print_line("Character count", $element->chars);  

printf("\n%20s\n", "* Parent elements");  

// 在该元素的父中循环,输出结果
while(list($key, $value) = each($element->parents))  
{  
print_line($key, $value);  
}  
if(count($element->parents) == 0)  
{  
printf("%35s\n", "[root element]");  
}  

// 在该元素的子中循环,输出结果
printf("\n%20s\n", "* Child elements");  
while(list($key, $value) = each($element->childs))  
{  
print_line($key, $value);  
}  
if(count($element->childs) == 0)  
{  
printf("%35s\n", "[no childs]");  
}  

$total_elements += $element->count;  
$total_chars += $element->chars;  
}  

// 最终结果
print_box("Total elements", $total_elements);  
print_box("Total characters", $total_chars);  
?> 



声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
解决方法:您的组织要求您更改 PIN 码解决方法:您的组织要求您更改 PIN 码Oct 04, 2023 pm 05:45 PM

“你的组织要求你更改PIN消息”将显示在登录屏幕上。当在使用基于组织的帐户设置的电脑上达到PIN过期限制时,就会发生这种情况,在该电脑上,他们可以控制个人设备。但是,如果您使用个人帐户设置了Windows,则理想情况下不应显示错误消息。虽然情况并非总是如此。大多数遇到错误的用户使用个人帐户报告。为什么我的组织要求我在Windows11上更改我的PIN?可能是您的帐户与组织相关联,您的主要方法应该是验证这一点。联系域管理员会有所帮助!此外,配置错误的本地策略设置或不正确的注册表项也可能导致错误。即

Windows 11 上调整窗口边框设置的方法:更改颜色和大小Windows 11 上调整窗口边框设置的方法:更改颜色和大小Sep 22, 2023 am 11:37 AM

Windows11将清新优雅的设计带到了最前沿;现代界面允许您个性化和更改最精细的细节,例如窗口边框。在本指南中,我们将讨论分步说明,以帮助您在Windows操作系统中创建反映您的风格的环境。如何更改窗口边框设置?按+打开“设置”应用。WindowsI转到个性化,然后单击颜色设置。颜色更改窗口边框设置窗口11“宽度=”643“高度=”500“&gt;找到在标题栏和窗口边框上显示强调色选项,然后切换它旁边的开关。若要在“开始”菜单和任务栏上显示主题色,请打开“在开始”菜单和任务栏上显示主题

如何在 Windows 11 上更改标题栏颜色?如何在 Windows 11 上更改标题栏颜色?Sep 14, 2023 pm 03:33 PM

默认情况下,Windows11上的标题栏颜色取决于您选择的深色/浅色主题。但是,您可以将其更改为所需的任何颜色。在本指南中,我们将讨论三种方法的分步说明,以更改它并个性化您的桌面体验,使其具有视觉吸引力。是否可以更改活动和非活动窗口的标题栏颜色?是的,您可以使用“设置”应用更改活动窗口的标题栏颜色,也可以使用注册表编辑器更改非活动窗口的标题栏颜色。若要了解这些步骤,请转到下一部分。如何在Windows11中更改标题栏的颜色?1.使用“设置”应用按+打开设置窗口。WindowsI前往“个性化”,然

OOBELANGUAGE错误Windows 11 / 10修复中出现问题的问题OOBELANGUAGE错误Windows 11 / 10修复中出现问题的问题Jul 16, 2023 pm 03:29 PM

您是否在Windows安装程序页面上看到“出现问题”以及“OOBELANGUAGE”语句?Windows的安装有时会因此类错误而停止。OOBE表示开箱即用的体验。正如错误提示所表示的那样,这是与OOBE语言选择相关的问题。没有什么可担心的,你可以通过OOBE屏幕本身的漂亮注册表编辑来解决这个问题。快速修复–1.单击OOBE应用底部的“重试”按钮。这将继续进行该过程,而不会再打嗝。2.使用电源按钮强制关闭系统。系统重新启动后,OOBE应继续。3.断开系统与互联网的连接。在脱机模式下完成OOBE的所

Windows 11 上启用或禁用任务栏缩略图预览的方法Windows 11 上启用或禁用任务栏缩略图预览的方法Sep 15, 2023 pm 03:57 PM

任务栏缩略图可能很有趣,但它们也可能分散注意力或烦人。考虑到您将鼠标悬停在该区域的频率,您可能无意中关闭了重要窗口几次。另一个缺点是它使用更多的系统资源,因此,如果您一直在寻找一种提高资源效率的方法,我们将向您展示如何禁用它。不过,如果您的硬件规格可以处理它并且您喜欢预览版,则可以启用它。如何在Windows11中启用任务栏缩略图预览?1.使用“设置”应用点击键并单击设置。Windows单击系统,然后选择关于。点击高级系统设置。导航到“高级”选项卡,然后选择“性能”下的“设置”。在“视觉效果”选

Windows 11 上的显示缩放比例调整指南Windows 11 上的显示缩放比例调整指南Sep 19, 2023 pm 06:45 PM

在Windows11上的显示缩放方面,我们都有不同的偏好。有些人喜欢大图标,有些人喜欢小图标。但是,我们都同意拥有正确的缩放比例很重要。字体缩放不良或图像过度缩放可能是工作时真正的生产力杀手,因此您需要知道如何对其进行自定义以充分利用系统功能。自定义缩放的优点:对于难以阅读屏幕上的文本的人来说,这是一个有用的功能。它可以帮助您一次在屏幕上查看更多内容。您可以创建仅适用于某些监视器和应用程序的自定义扩展配置文件。可以帮助提高低端硬件的性能。它使您可以更好地控制屏幕上的内容。如何在Windows11

10种在 Windows 11 上调整亮度的方法10种在 Windows 11 上调整亮度的方法Dec 18, 2023 pm 02:21 PM

屏幕亮度是使用现代计算设备不可或缺的一部分,尤其是当您长时间注视屏幕时。它可以帮助您减轻眼睛疲劳,提高易读性,并轻松有效地查看内容。但是,根据您的设置,有时很难管理亮度,尤其是在具有新UI更改的Windows11上。如果您在调整亮度时遇到问题,以下是在Windows11上管理亮度的所有方法。如何在Windows11上更改亮度[10种方式解释]单显示器用户可以使用以下方法在Windows11上调整亮度。这包括使用单个显示器的台式机系统以及笔记本电脑。让我们开始吧。方法1:使用操作中心操作中心是访问

如何修复Windows服务器中的激活错误代码0xc004f069如何修复Windows服务器中的激活错误代码0xc004f069Jul 22, 2023 am 09:49 AM

Windows上的激活过程有时会突然转向显示包含此错误代码0xc004f069的错误消息。虽然激活过程已经联机,但一些运行WindowsServer的旧系统可能会遇到此问题。通过这些初步检查,如果这些检查不能帮助您激活系统,请跳转到主要解决方案以解决问题。解决方法–关闭错误消息和激活窗口。然后,重新启动计算机。再次从头开始重试Windows激活过程。修复1–从终端激活从cmd终端激活WindowsServerEdition系统。阶段–1检查Windows服务器版本您必须检查您使用的是哪种类型的W

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),