xml解析技术_先进的XML解析技术

xml解析技术

PHP5提供了改进的各种XML解析技术。 现在基于libxml2的James Clark的Expat SAX解析器不再是城里唯一的全功能游戏。 完全符合W3C标准的DOM解析是一种常见的选择。 您在第1部分中看到的SimpleXML(请参阅参考资料 )和比SAX更容易,更快的XMLReader都提供了其他解析方法。 现在,所有XML扩展都基于GNOME项目的libxml2库。 这个统一的库允许不同扩展之间的互操作性。 本文将介绍PHP5的XML解析技术,重点是解析大型或复杂的XML文档。 它将提供一些有关解析技术的背景知识,哪种方法最适合哪种类型的XML文档,以及(如果可以选择的话)选择的标准。

SimpleXML

第1部分提供了有关XML的基本信息,并重点介绍了快速入门的应用程序编程接口(API)。 它说明了如果您使用简单,可预测且相对基本的XML文档,那么将SimpleXML与必要的文档对象模型(DOM)相结合是理想的选择。

XML和PHP5

可扩展标记语言(XML)被描述为标记语言和基于文本的数据存储格式。 它提供了一种基于文本的方法,可以对信息应用和描述基于树的结构。

在PHP5中,存在用于解析XML的全新的和重写的扩展。 将整个XML文档加载到内存中的组件包括SimpleXML,DOM和XSLT处理器。 一次为您提供一份XML文档的解析器包括XML的简单API(SAX)和XMLReader。 SAX的功能与PHP4中的功能相同,但它不再基于expat库,而是基于libxml2库。 如果您熟悉其他语言的DOM,则与以前的版本相比,用PHP5用DOM编码的时间会更容易。

XML解析基础

解析XML的两种基本方法是:树和流。 树样式解析涉及将整个XML文档加载到内存中。 树形文件结构允许对文档元素的随机访问和XML的编辑。 树型解析的示例包括DOM和SimpleXML。 它们在内存中以不同但可互操作的格式共享树状结构。 与树样式解析不同,流解析不会将整个XML文档加载到内存中。 在此上下文中,术语流的使用与流音频中的术语流紧密对应。 它在做什么以及为什么这样做是完全相同的,即一次传送少量数据以保留带宽和内存。 在流解析中,仅可访问当前正在解析的节点,并且无法将XML作为文档进行编辑。 流解析器的示例包括XMLReader和SAX。

基于树的解析器

基于树的解析器之所以如此命名是因为它们将整个XML文档加载到内存中,其中文档根为主干,而所有子代,孙代,后代和属性均为分支。 最熟悉的基于树的解析器是DOM。 最简单的基于树的语法分析器是SimpleXML。 您将同时看到两者。

与DOM解析

根据W3C,DOM标准是“ ...一个平台和语言无关的接口,它将允许程序和脚本动态访问和更新文档的内容,结构和样式。” GNOME项目的libxml2库在C中实现了DOM及其所有方法。由于所有PHP5 XML扩展都基于libxml2,因此扩展之间具有完全的互操作性。 这种互操作性大大增强了它们的功能。 例如,您可以使用流解析器XMLReader来获取元素,将其导入DOM并使用XPath提取数据。 那是很大的灵活性。 您将在清单5中看到这一点。

DOM是基于树的解析器。 DOM易于理解和利用,因为它在内存中的结构类似于原始XML文档。 DOM通过创建对象树来将信息传递给应用程序,该对象树精确复制XML文件中的元素树,每个XML元素都是树中的一个节点。 DOM是W3C标准,由于它与其他编程语言保持一致,因此赋予了DOM与开发人员很多的权限。 因为DOM构建了整个文档的树,所以它会占用大量内存和处理器时间。

行动中的DOM

如果您因设计或任何其他约束而被迫成为解析器领域的一把手小马,那么这里就是您想要的唯一灵活性。 使用DOM,您可以构建,修改,查询,验证和转换XML文档。 您可以使用所有DOM方法和属性。 大多数DOM 2级方法都是通过适当支持的属性来实现的。 由于其巨大的灵活性,使用DOM解析的文档可能会变得很复杂。 但是请记住,如果一次将一个大型XML文档全部加载到内存中,那么灵活性的代价是有代价的。

清单1中的示例使用DOM解析文档,并使用getElementById检索元素。 在引用ID之前,必须通过设置validateOnParse=true来验证文档。 根据DOM标准,这需要将属性ID定义为ID类型的DTD。

清单1.将DOM与基本文档一起使用
<?php

$doc = new DomDocument;

// We must validate the document before referring to the id
$doc->validateOnParse = true;
$doc->Load('basic.xml');

echo "The element whose id is myelement is: " . 
$doc->getElementById('myelement')->tagName . "\n";

?>

getElementsByTagName()函数返回DOMNodeList类的新实例,该实例包含具有给定标签名称的元素。 当然,该列表必须经过。 在迭代由getElementsByTagName()返回的NodeList时更改文档结构会影响您正在迭代的NodeList (请参见清单2)。 没有验证要求。

清单2. DOM getElementsByTagName方法
DOMDocument {
  DOMNodeList getElementsByTagName(string name);
}

清单3中的示例将DOM与XPath结合使用。

清单3.使用DOM并使用XPath进行解析
<?php

$doc = new DOMDocument;

// We don't want to bother with white spaces
$doc->preserveWhiteSpace = false;

$doc->Load('book.xml');

$xpath = new DOMXPath($doc);

// We start from the root element
$query = '//book/chapter/para/informaltable/tgroup/tbody/row/entry[. = "en"]';

$entries = $xpath->query($query);

foreach ($entries as $entry) {
   echo "Found {$entry->previousSibling->previousSibling->nodeValue}," .
        " by {$entry->previousSibling->nodeValue}\n";
}
?>

说完DOM的所有这些方面之后,我将以一个示例说明如何与DOM无关,以便尽可能地强调观点,然后在下一个示例中,救你自己。 清单4展示了将一个大文件加载到DOM中只是为了从具有DomXpath的单个属性中提取数据。

清单4.在大型XML文档上以错误的方式将DOM与XPath一起使用
<?php

// Parsing a Large Document with DOM and DomXpath
// First create a new DOM document to parse
$dom = new DomDocument();

//  This document is huge and we don't really need anything from the tree
//  This huge document uses a huge amount of memory 
$dom->load("tooBig.xml");
$xp = new DomXPath($dom);
$result = $xp->query("/blog/entries/entry[@ID = 5225]/title") ;
print $result->item(0)->nodeValue ."\n";

?>

清单5中的最后一个后续示例以相同的方式使用DOM和XPath,不同之处在于XMLReader使用expand()一次将数据传递给一个元素。 使用此方法,可以将XMLReader传递的节点转换为DOMElement

清单5.在大型XML文档上以正确的方式将DOM与XPath一起使用
<?php

// Parsing a large document with XMLReader with Expand - DOM/DOMXpath 
$reader = new XMLReader();

$reader->open("tooBig.xml");

while ($reader->read()) {
    switch ($reader->nodeType) {
        case (XMLREADER::ELEMENT):
        if ($reader->localName == "entry") {
            if ($reader->getAttribute("ID") == 5225) {
                $node = $reader->expand();
                $dom = new DomDocument();
                $n = $dom->importNode($node,true);
                $dom->appendChild($n);
                $xp = new DomXpath($dom);
                $res = $xp->query("/entry/title");
                echo $res->item(0)->nodeValue;
            }
        }
    }
}
    
?>

用SimpleXML解析

SimpleXML扩展名是解析XML文档的另一种选择。 SimpleXML扩展需要PHP5并包括内置的XPath支持。 SimpleXML最适合简单的基本XML数据。 只要XML文档没有太复杂,太深并且缺少混合内容,就如其名称所暗示的那样,SimpleXML比DOM更易于使用。 如果使用已知的文档结构,则将更加直观。

运行中的SimpleXML

SimpleXML具有DOM的许多优点,并且更易于编码。 它可以轻松访问XML树,具有内置的验证和XPath支持,并且可以与DOM互操作,从而提供对XML文档的读写支持。 您可以简单快速地编写使用SimpleXML解析的文档。 但是请记住,与DOM一样,如果将大型XML文档加载到内存中,SimpleXML的易用性和灵活性也要付出代价。

清单6中的以下代码从示例XML中提取<plot>。

清单6.提取绘图文本
<?php
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<books>
   <book>
      <title>Great American Novel</title>
      <plot>
         Cliff meets Lovely Woman. Loyal Dog sleeps, but
         wakes up to bark at mailman.
      </plot>
      <success type="bestseller">4</success>
      <success type="bookclubs">9</success>
   </book>
</books>
XML;
?>
<?php

$xml = new SimpleXMLElement($xmlstr);
echo $xml->book[0]->plot; // "Cliff meets Lovely Woman. ..."
?>

另一方面,您可能希望提取多行地址。 当一个元素的多个实例作为单个父元素的子代存在时,将应用常规迭代技术。 清单7中的以下代码演示了此功能。

清单7.提取一个元素的多个实例
<?php
$xmlstr = <<<XML
<xml version='1.0' standalone='yes'?>
<books>
   <book>
      <title>Great American Novel</title>
      <plot>
         Cliff meets Lovely Woman.
      </plot>
      <success type="bestseller">4</success>
      <success type="bookclubs">9</success>
   </book>
   <book>
      <title>Man Bites Dog</title>
      <plot>
         Reporter invents a prize-winning story.
      </plot>
      <success type="bestseller">22</success>
      <success type="bookclubs">3</success>
   </book>
</books>
XML;
?>
<php

$xml = new SimpleXMLElement($xmlstr);

foreach ($xml->book as $book) {
   echo $book->plot, '<br />';
}
?

除了读取元素名称及其值之外,SimpleXML还可以访问元素属性。 在清单8所示的代码中,您就像访问数组元素一样访问元素的属性。

清单8.演示SimpleXML访问元素的属性
<?php
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<books>
   <book>
      <title>Great American Novel</title>
      <plot>
         Cliff meets Lovely Woman.
      </plot>
      <success type="bestseller">4</success>
      <success type="bookclubs">9</success>
   </book>
   <book>
      <title>Man Bites Dog</title>
      <plot>
         Reporter invents a prize-winning story.
      <plot>
      <success type="bestseller">22</success>
      <success type="bookclubs">3</success>
   </book>
<books>
XML;
?>
<?php

$xml = new SimpleXMLElement($xmlstr);

foreach ($xml->book[0]->success as $success) {
   switch((string) $success['type']) {
   case 'bestseller':
      echo $success, ' months on bestseller list<br />';
      break;
   case 'bookclubs':
      echo $success, ' bookclub listings<br />';
      break;
   }
}

?>

最后一个示例(参见清单9)将SimpleXML和DOM与XMLReader 。 使用XMLReader ,使用expand()一次将数据传递给一个元素。 使用此方法,可以将XMLReader传递的节点转换为DOMElement ,然后转换为SimpleXML。

清单9.将SimpleXML与DOM和XMLReader一起使用以解析大型XML文档
<?php

// Parsing a large document with Expand and SimpleXML
$reader = new XMLReader();

$reader->open("tooBig.xml");

while ($reader->read()) {
    switch ($reader->nodeType) {
        case (XMLREADER::ELEMENT):
        if ($reader->localName == "entry") {
            if ($reader->getAttribute("ID") == 5225) {
                $node = $reader->expand();
                $dom = new DomDocument();
                $n = $dom->importNode($node,true);
                $dom->appendChild($n);
                $sxe = simplexml_import_dom($n);
                echo $sxe->title; 
            }
        }
    }
}
    
?>

基于流的解析器

基于流的解析器之所以如此命名,是因为它们以与流音频几乎相同的原理解析流中的XML,并使用特定的节点,并且当它们完成该节点时,完全忘记了它的存在。 XMLReader是拉式解析器,您可以使用与游标中的数据库查询结果表相同的方式为其编写代码。 这样可以更轻松地处理不熟悉或无法预测的XML文件。

用XMLReader解析

XMLReader扩展名是基于流的解析器,其类型通常称为游标类型或提取解析器。 XMLReader根据请求从XML文档中提取信息。 它基于从C#XmlTextReader派生的API。 默认情况下,它在PHP 5.1中包含并启用,并且基于libxml2。 在PHP 5.1之前,XMLReader扩展默认情况下未启用,但在PECL中可用(请参阅参考资料中的链接)。 XMLReader支持名称空间和验证,包括DTD和Relaxed NG。

使用XMLReader

XMLReader作为流解析器,非常适合解析大型XML文档。 它比SAX编码容易得多,并且通常更快。 这是您选择的流解析器。

清单10中的示例使用XMLReader解析大型XML文档。

清单10.带有大型XML文件的XMLReader
<?php

$reader = new XMLReader();
$reader->open("tooBig.xml");
while ($reader->read()) {
   switch ($reader->nodeType) {
   case (XMLREADER::ELEMENT):
      if ($reader->localName == "entry") {
         if ($reader->getAttribute("ID") == 5225) {
            while ($reader->read()) {
               if ($reader->nodeType == XMLREADER::ELEMENT) {
                  if ($reader->localName == "title") {
                     $reader->read();
                     echo $reader->value;
                     break;
                  }
                  if ($reader->localName == "entry") {
                     break;
                  }
               }
            }
         }
      }
   }
}
?>

用SAX解析

XML的简单API(SAX)是流解析器。 事件与正在读取的XML文档相关联,因此SAX被编码在回调中。 对于元素打开和关闭标签,元素内容,实体以及错误分析,都有事件。 使用SAX解析器而不是XMLReader的主要原因是,SAX解析器有时效率更高,通常更熟悉。 一个主要的缺点是SAX解析器代码比XMLReader代码更复杂且更难编写。

行动中的SAX

对于使用PHP4中的XML的人来说,SAX可能很熟悉,而PHP5中的SAX扩展与他们以前使用的版本兼容。 由于它是流解析器,因此对于大文件来说是一个不错的选择,但不如XMLReader那样好。

清单11中的示例使用SAX解析大型XML文档。

清单11.使用SAX解析大型XML文件
<?php

//This class contains all the callback methods that will actually
//handle the XML data.
class SaxClass {
   private $hit = false;
   private $titleHit = false;

   //callback for the start of each element
   function startElement($parser_object, $elementname, $attribute) {
      if ($elementname == "entry") {
         if ( $attribute['ID'] == 5225) {
            $this->hit = true;
         } else {
            $this->hit = false;
         }
      }
      if ($this->hit && $elementname == "title") {
         $this->titleHit = true;
      } else {
         $this->titleHit =false;
      }
   }

   //callback for the end of each element
   function endElement($parser_object, $elementname) {
   }

   //callback for the content within an element
   function contentHandler($parser_object,$data)
   {
      if ($this->titleHit) {
         echo trim($data)."<br />";
      }
   }
}

//Function to start the parsing once all values are set and
//the file has been opened
function doParse($parser_object) {
   if (!($fp = fopen("tooBig.xml", "r")));

   //loop through data
   while ($data = fread($fp, 4096)) {
      //parse the fragment
      xml_parse($parser_object, $data, feof($fp));
   }
}

$SaxObject = new SaxClass();
$parser_object = xml_parser_create();
xml_set_object ($parser_object, $SaxObject);

//Don't alter the case of the data
xml_parser_set_option($parser_object, XML_OPTION_CASE_FOLDING, false);

xml_set_element_handler($parser_object,"startElement","endElement");
xml_set_character_data_handler($parser_object, "contentHandler");

doParse($parser_object);

?>

摘要

PHP5提供了多种改进的解析技术。 现在完全符合W3C标准的DOM解析是一种常见的选择,并且是复杂但相对较小的文档的选择。 SimpleXML是处理基本的和不太大的XML文档的方法,并且XMLReader比SAX容易和快捷,是大型文档的首选流解析器。


翻译自: https://www.ibm.com/developerworks/opensource/library/x-xmlphp2/index.html

xml解析技术

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值