【问题标题】:XML end element is read twice using XMLReader with PHP使用 XMLReader 和 PHP 读取 XML 结束元素两次
【发布时间】:2011-06-30 23:06:21
【问题描述】:

我想使用 XMLReader 读取 XML 文件,但在解析过程中每个元素都会调用 END ELEMENT 两次。

<publications>
  <article id="Xu86oazdn">
    <title>Learning</title>
    <authors>
      <author>
        <firstname>Michel</firstname>
        <lastname>Browsky</lastname>
      </author>
    </authors>
  </article>
</publications>

这是解析作者条目的一段代码:

<?php
$xml = new XMLReader();
$xml->open("php://stdin");
$author = null;

while($xml->read()) {

  switch($xml->nodeType) {
    case XMLReader::ELEMENT:
      switch($xml->name) {
        case 'author':
          echo("+" . $xml->name);
          break;
    }

    case XMLReader::END_ELEMENT:
      switch($xml->name) {
        case 'author':
          echo("-" . $xml->name);
          break;
      }
    }
  }
?>

但奇怪的是,每个&lt;/author&gt; 都会调用 END_ELEMENT 两次,如回显消息所示:

+author
-author
-author

如果我通过调用 $xml-&gt;readOuterXML() 来替换回显消息,则第一个 END_ELEMENT 如下:

<author>
  <firstname>Michel</firstname>
  <lastname>Browsky</lastname>
</author>

第二个如下:

<author/>

我的代码有什么问题?我是否以错误的方式使用了 END_ELEMENT ?检测结束元素的正确方法是什么?

【问题讨论】:

    标签: php xml xmlreader


    【解决方案1】:

    nodeType 的第一个switch 条件结束后添加break 语句:

    <?php
    $xml = new XMLReader();
    $xml->open("php://stdin");
    
    while($xml->read()) {
    
      switch($xml->nodeType) {
        case XMLReader::ELEMENT:
          switch($xml->name) {
            case 'author':
              echo("+" . $xml->name);
              break;
        }
    
        // THIS LINE IS MISSING
        break;
    
        case XMLReader::END_ELEMENT:
          switch($xml->name) {
            case 'author':
              echo("-" . $xml->name);
              break;
          }
        }
      }
    ?>
    

    在阅读END_ELEMENT 之后再添加一个break,如果只是为了对称的话。

        case XMLReader::END_ELEMENT:
          switch($xml->name) {
            case 'author':
              echo("-" . $xml->name);
              break;
          }
        }
    
        break;
    

    问题是由于编码风格而发生的。简化代码。例如:

    $xml = new XMLReader();
    $xml->open("php://stdin");
    
    while($xml->read()) {    
      switch($xml->nodeType) {
        case XMLReader::ELEMENT: {
          startElement( $xml->name );
          break;
        }
    
        case XMLReader::END_ELEMENT: {
          endElement( $xml->name );
          break;
        }
      }
    }
    

    您还可以进行进一步的简化。 PHP 有一个 XML 编组包,但您也可以将代码抽象为类。然后,这些类的实例将能够从(或向)XML 文件读取(或写入)它们自己。例如:

    $xml = new XMLReader();
    $xml->open("php://stdin");
    
    while($xml->read()) {    
      if( $xml->name == 'author' ) {
        $author = new Author();
        $author->marshall( $xml );
      }
    }
    

    这将对象如何存储的细节与对象本身结合在一起。每当您更改 Author 对象时,您都知道您必须更改它的编组方式。您可以使用适当的设计模式、XML 模式等进一步抽象和扩展这些概念。

    因此您的最终代码可能类似于:

    $xml = new XMLReader();
    $xml->open( "php://stdin" );
    $publications = new Publications();
    $publications->marshall( $xml );
    

    Publications 对象负责读取 XML 文档并在其关联的 XML 标记出现时实例化适当的类:

    while($xml->read()) {    
      $article = new Article();
      $article->marshall( $xml );
      add( $article );
    }
    

    使用 PHP 编组框架可以节省您的时间和精力。考虑 XML_Serializer:

    【讨论】:

      猜你喜欢
      • 2016-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-08
      • 2014-05-31
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      相关资源
      最近更新 更多