为什么这个XPath查询失败?我在DOMXPath上犯了错误吗?

时间:2011-01-13 15:47:58

标签: php dom xpath

这个问题有点复杂,因为有很多移动部件,但我会尝试缩小并仅使用最相关的片段。

我正在研究基于PHP中DOM类的XML / XHTML文档解析器,但似乎使用DOMXPath的部分失败了。鉴于此示例文档:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:zuq="http://localhost/~/zuqml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body>
    <h1 id="pageHeading">
        <zuq:data name="pageHeading" />
    </h1>
    <p id="pageDescription">
        <zuq:data name="pageDescription">
            <zuq:format type="trim">
                <zuq:param name="length">300</zuq:param>
                <zuq:param name="append">...</zuq:param>
            </zuq:format>
        </zuq:data>
    </p>
    <div id="toolbar">
        <zuq:region name="toolbar" />
    </div>
    <div id="postWrap">
        <zuq:region name="post">
            <div class="post">
                <img height="200" width="200">
                    <zuq:attr name="src">
                        ./src/<zuq:data name="postImageSrc" />
                    </zuq:attr>
                </img>
                <h2><zuq:data name="postHeading" /></h2>
                <p>
                    <zuq:data name="postBody">
                        <zuq:format type="trim">
                            <zuq:param name="length">300</zuq:param>
                            <zuq:param name="append">
                                <a>
                                    <zuq:attr name="href">
                                        ./?postId=<zuq:data name="postId" />
                                    </zuq:attr>
                                    More »
                                </a>
                            </zuq:param>
                        </zuq:format>
                    </zuq:data>
                </p>
            </div>
        </zuq:region>
    </div>
</body>
</html>

我创建了一个解析器,它接受一个DataObject对象(实际上只是一个其他DataObject对象的奇特树),并使用树中的数据循环解析文档。文档源路径也存储在树中。

解析器构造函数:

public function __construct(DataObject $dataObject){
    $this->_dataObject = $dataObject;
}

公共render方法,用于将文档作为字符串返回:

public function render($filename = null){
    $document = new DOMDocument;
    $frag = $this->_build($document, $this->_dataObject);
    if(is_null($filename)){
        return $document->saveXML($frag);
    }else{
        //render to file
    }
}

最后是私人_build方法,其中发生了行动的主要内容:

protected function _build(DOMNode $node, DataObject $dataObject){
    $ownerDocument = $node instanceof DOMDocument
        ? $node
        : $node->ownerDocument;

    $buffer = $ownerDocument->createDocumentFragment();    

    for($dataIndex = 0; $dataIndex < $dataObject->count(); $dataIndex++){

        $frag = $ownerDocument->createDocumentFragment();
        if(!$dataObject->hasParent() || ($dataObject->getFilename() != $dataObject->getParent()->getFilename())){
            $frag->appendXML(file_get_contents($dataObject->getFilename()));
        }else{
            foreach($node->childNodes as $child){
                $frag->appendChild($child->cloneNode(true));
            }
        }
        $frag->normalize();

        $xpath = new DOMXPath($ownerDocument);
        $xpath->registerNamespace('zuq', $ownerDocument->lookupNamespaceURI('zuq'));

        //THIS IS WHERE THE TROUBLES ARE
        $nodeList = $xpath->query('.//zuq:data[not(ancestor::zuq:region)]', $frag);

        for($nodeIndex = $nodeList->length - 1; $nodeIndex >= 0; $nodeIndex--){

            //PERFORM REPLACEMENTS

        }
        $buffer->appendChild($frag);
    }
    return $buffer;
}

我知道这是一大块,但如果有问题,那就必须在那里。 问题是XPath查询没有返回任何节点。我已经在文档上完全测试了它,它运行正常。它在给定节点的上下文中找到所有<zuq:data />元素之外的所有<zuq:region />元素(在递归中是区域,但我还没有),这将允许解析每个区域单独水平。

当我使用$nodeList = $xpath->query('.//*', $frag);并循环生成$nodeList时,它包含所有文档元素,从<html>到最嵌套。

为什么我的$nodeList = $xpath->query('.//zuq:data[not(ancestor::zuq:region)]', $frag);查询失败了?我真的希望这很简单,“哦,你只是忘了 _ _。”

事先,我真的很感激任何帮助,如果有更多细节需要,我很乐意提供,请告诉我。

1 个答案:

答案 0 :(得分:2)

  

查询失败了吗?我真的希望如此   这是一个简单的问题,“哦,你只是   忘了__。“

我认为就是这样。使用比'http://localhost/~/zuqml'

更好的静态URI $ownerDocument->lookupNamespaceURI('zuq')