Этот вопрос немного сложен, так как есть много движущихся частей, но я постараюсь минимизировать и использовать только самые подходящие фрагменты.
Я работаю над анализатором документов XML / XHTML, основанным на классах DOM
в PHP, но похоже, что часть, использующая 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);
запрос не выполняется? Я действительно надеюсь, что все просто: «О, вы просто забыли _ _.»
Заранее, я очень признателен за любую помощь, и, если потребуется более подробная информация, я был бы рад предоставить, просто дайте мне знать.