У меня есть файл, который выглядит так:
<ExternalPage about="http://animation.about.com/"> <d:Title>About.com: Animation Guide</d:Title> <d:Description>Keep up with developments in online animation for all skill levels. Download tools, and seek inspiration from online work.</d:Description> <topic>Top/Arts/Animation</topic> </ExternalPage> <ExternalPage about="http://www.toonhound.com/"> <d:Title>Toonhound</d:Title> <d:Description>British cartoon, animation and comic strip creations - links, reviews and news from the UK.</d:Description> <topic>Top/Arts/Animation</topic> </ExternalPage>
и т.п.
Я пытаюсь получить URL-адрес «about», а также вложенный заголовок и описание. Я пробовал следующий код, но все, что я получаю, это куча тире …
$reader = new XMLReader(); if (!$reader->open("dbpedia/links/xml.xml")) { die("Failed to open 'xml.xml'"); } $num=0; while($reader->read() && $num<200) { if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'ExternalPage') { $url = $reader->getAttribute('about'); while ($xml->nodeType !== XMLReader::END_ELEMENT ){ $reader->read(); if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'd:Title') { $title=$xmlReader->value; } elseif ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'd:Description') { $desc=$xmlReader->value; } } } $num++;echo $url."-".$title."-".$desc."<br />"; } $reader->close();
Я новичок в xmlreader, поэтому я был бы признателен, если бы кто-то мог понять, что я делаю неправильно.
Примечание. Я использую xmlreader, потому что файл является огромным (миллионы строк).
EDIT: начало файла выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8"?> <RDF xmlns:r="http://www.w3.org/TR/RDF/" xmlns:d="http://purl.org/dc/elements/1.0/" xmlns="http://dmoz.org/rdf/"> <!-- Generated at 2013-02-10 00:03:45 EST from DMOZ 2.0 --> <Topic r:id=""> <catid>1</catid> </Topic> <Topic r:id="Top/Arts"> <catid>381773</catid> </Topic> <Topic r:id="Top/Arts/Animation"> <catid>423945</catid> <link1 r:resource="http://www.awn.com/"></link1> <link r:resource="http://animation.about.com/"></link> <link r:resource="http://www.toonhound.com/"></link> <link r:resource="http://enculturation.gmu.edu/2_1/pisters.html"></link> <link r:resource="http://www.digitalmediafx.com/Features/animationhistory.html"></link> <link r:resource="http://www.spark-online.com/august00/media/romano.html"></link> <link r:resource="http://www.animated-divots.net/"></link> </Topic> <ExternalPage about="http://www.awn.com/"> <d:Title>Animation World Network</d:Title> <d:Description>Provides information resources to the international animation community. Features include searchable database archives, monthly magazine, web animation guide, the Animation Village, discussion forums and other useful resources.</d:Description> <priority>1</priority> <topic>Top/Arts/Animation</topic> </ExternalPage>
и т.д
Требуется время и правильная отладка, чтобы приступить к работе с чистым XMLReader-кодом. Между тем попробуйте этот гибридный метод:
$xmlR = new XMLReader; $xmlR->open('dbpedia/links/xml.xml'); //Skip until <ExternalPage> node while ($xmlR->read() && $xmlR->name !== 'ExternalPage'); $loadedNS_f = false; while ($xmlR->name === 'ExternalPage') { //Read the entire parent tag with children $sxmlNode = new SimpleXMLElement($xmlR->readOuterXML()); //collect all namespaces in node recursively once; assuming all nodes are similar if (!$loadedNS_f) { $tagNS = $sxmlNode->getNamespaces(true); $loadedNS_f = true; } $URL = (string) $sxmlNode['about']; $dNS = $sxmlNode->children($tagNS['d']); $Title = (string) $dNS->Title; $Desc = (string) $dNS->Description; $Topic = (string)$sxmlNode->topic; var_dump($URL, $Title, $Desc, $Topic); // Jump to next <ExternalPage> tag $xmlR->next('ExternalPage'); } $xmlR->close();
Причина, по которой он не работает для вас, заключается в том, что вы только читаете начальный тег элемента d:Title
и не получили никакого значения:
if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'd:Title') { $title=$xmlReader->value; }
Вероятно, вы хотели получить nodeValue этого элемента DOM, но это не то, что $xmlReader->value
. Зная это, есть несколько способов справиться с этим:
Разверните узел ( XMLReader::expand()
) и получите nodeValue
(быстрый пример):
$title = $reader->expand()->nodeValue;
Обработайте все XMLReader::TEXT (3)
и / или XMLReader::CDATA (4)
дочерние узлы самостоятельно (решите, является ли узел дочерним узлом, просмотрев XMLReader::$depth
).
В любом случае, чтобы упорядочить код, вы можете подумать о том, чтобы предоставить то, что вам нужно напрямую, например, создав себе набор собственных функций или расширить класс XMLReader:
class MyXMLReader extends XMLReader { public function readToNextElement() { while ( $result = $this->read() and $this->nodeType !== self::ELEMENT ) ; return $result; } public function readToNext($localname) { while ( $result = $this->readToNextElement() and $this->localName !== $localname ) ; return $result; } public function readToNextChildElement($depth) { // if the current element is the parent and // empty there are no children to go into if ($this->depth == $depth && $this->isEmptyElement) { return false; } while ($result = $this->read()) { if ($this->depth <= $depth) return false; if ($this->nodeType === self::ELEMENT) break; } return $result; } public function getNodeValue($default = NULL) { $node = $this->expand(); return $node ? $node->nodeValue : $default; } }
Затем вы можете просто использовать этот расширенный класс для обработки:
$reader = new MyXMLReader(); $reader->open($uri); $num = 0; while ($reader->readToNext('ExternalPage') and $num < 200) { $url = $reader->getAttribute('about'); $depth = $reader->depth; $title = $desc = ''; while ($reader->readToNextChildElement($depth)) { switch ($reader->localName) { case 'Title': $title = $reader->getNodeValue(); break; case 'Description': $desc = trim($reader->getNodeValue()); break; } } $num++; echo "#", $num, ": ", $url, " - ", $title, " - ", $desc, "<br />\n"; }
Как вы можете видеть, это значительно улучшило ваш код. Также вам не нужно заботиться каждый раз, если вы читаете все правильно.
Вот альтернативный способ получить этот атрибут:
$string = file_get_contents($filename); $xml = new SimpleXMLElement($string); $result = $xml->xpath('/RDF/ExternalPage[*]/@about'); var_dump($result);