// set up the request 
  $request = $HTTP_RAW_POST_DATA; 
  error_reporting(E_ERROR | E_WARNING | E_PARSE); 
  if (isset($php_errormsg)) unset(($php_errormsg); 
  // create the reader 
  $reader = new XMLReader(); 
  // $reader->setRelaxNGSchema("request.rng"); 
  $reader->XML($request); 
  $input = ""; 
  while ($reader->read()) { 
  if ($reader->name == "double" && $reader->nodeType == XMLReader::ELEMENT) { 
  while ($reader->read()) { 
  if ($reader->nodeType == XMLReader::TEXT 
  || $reader->nodeType == XMLReader::CDATA 
  || $reader->nodeType == XMLReader::WHITESPACE 
  || $reader->nodeType == XMLReader::SIGNIFICANT_WHITESPACE) { 
  $input .= $reader->value; 
  } 
  else if ($reader->nodeType == XMLReader::END_ELEMENT 
  && $reader->name == "double") { 
  break; 
  } 
  } 
  break; 
  } 
  } 
  // make sure the input was well-formed 
  if (isset($php_errormsg) ) fault(21, $php_errormsg); 
  else if ($input < 0) fault(20, "Cannot take square root of negative number"); 
  else respond($input);
  这是 XML 流处理中简单的常见模式。解析器将填写一个数据结构,当完成文档时该数据结构将起作用。通常数据结构要比文档本身简单。这里所使用的数据结构尤其简单:一个字符串。
  验证
  到目前为止,对于验证数据是否位于所预期的地方,并没有给予关注。实现该验证的最简单的方法是检查文档的模式。XMLReader 支持 RELAX NG 模式语言;清单 9 展示了简单的 RELAX NG 模式,用于这个特定的 XML-RPC 请求表单。
  libxml 版本 
  在 libxml 的早期版本中,RELAX NG 有一些严重错误,XMLReader 取决于 libxml 库。请确保所使用的版本至少是 2.06.26 版。很多系统(包括 Mac OS X Tiger)捆绑了较早的、有错误的 libxml 版本。
  清单 9. XML-RPC 请求
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
sqrt
  可以使用 setRelaxNGSchemaSource() 将模式作为一串文字直接嵌入 PHP 脚本,或者使用 setRelaxNGSchema() 从外部文件或 URL 读取模式。例如,假定清单 9 位于 sqrt.rng 文件中,下面将展示如何载入模式:
   
reader->setRelaxNGSchema("sqrt.rng")
  在开始解析文档 之前,执行上述操作。解析器在进行读取时将检查文档的模式。若要检查文档是否有效,则调用 isValid(),如果文档是有效的(目前为止),则返回 true,否则,返回 false。清单 10 展示了完整的程序,包括所有错误处理。这样将接受任何合法输入,然后返回正确的值,而且将拒绝所有不正确的请求。我还添加了 fault() 方法,当发生故障时将发送 XML-RPC 错误响应。
  清单 10. 完整的 XML-RPC 平方根服务器
   
header('Content-type: application/xml'); 
  // try grammar 
  $schema = " 
  xmlns='http://relaxng.org/ns/structure/1.0' 
  datatypeLibrary='http://www.w3.org/2001/XMLSchema-datatypes'> 
  sqrt 
  "; 
  if (!isset($HTTP_RAW_POST_DATA)) { 
  fault(22, "Please make sure always_populate_raw_post_data = On in php.ini"); 
  } 
  else { 
  // set up the request 
  $request = $HTTP_RAW_POST_DATA; 
  error_reporting(E_ERROR | E_WARNING | E_PARSE); 
  // create the reader 
  $reader = new XMLReader(); 
  $reader->setRelaxNGSchema("request.rng"); 
  $reader->XML($request); 
  $input = ""; 
  while ($reader->read()) { 
  if ($reader->name == "double" && $reader->nodeType == XMLReader::ELEMENT) { 
  while ($reader->read()) { 
  if ($reader->nodeType == XMLReader::TEXT 
  || $reader->nodeType == XMLReader::CDATA 
  || $reader->nodeType == XMLReader::WHITESPACE 
  || $reader->nodeType == XMLReader::SIGNIFICANT_WHITESPACE) { 
  $input .= $reader->value; 
  } 
  else if ($reader->nodeType == XMLReader::END_ELEMENT 
  && $reader->name == "double") { 
  break; 
  } 
  } 
  break; 
  } 
  } 
  if (isset($php_errormsg) ) fault(21, $php_errormsg); 
  else if (! $reader->isValid()) fault(19, "Invalid request"); 
  else if ($input < 0) fault(20, "Cannot take square root of negative number"); 
  else respond($input); 
  $reader->close(); 
  } 
  function respond($input) 
  { 
  ?> 
  echo sqrt($input); 
  ?> 
  } 
  function fault($code, $message) 
  { 
  echo " 
  faultCode 
  " . $code . " 
  faultString 
  " . $message . " 
  "; 
  }   
  属性
  在正常的推解析期间不会看到属性。若要读取属性,请停止在元素的起点处,通过名称或编号来请求特定属性。
  将需要的属性名称传递到 getAttribute(),以便在当前元素上查找该属性的值。例如,下面的语句请求当前元素的 id 属性:
   
$id = $reader->getAttribute("id");
  如果属性位于名称空间中 —— 例如,xlink:href —— 则调用 getAttributeNS(),将本地名称和名称空间 URI 分别作为第一个和第二个参数进行传递。(前缀是无关紧要的。)例如,下面的语句将请求 http://www.w3.org/1999/xlink/ 名称空间中 xlink:href 属性的值: