Kaynağa Gözat

Personnal XmlParser using trees

isundil 10 yıl önce
ebeveyn
işleme
826ea1904c
3 değiştirilmiş dosya ile 130 ekleme ve 21 silme
  1. 11 10
      test.php
  2. 111 0
      xmlParser.php
  3. 8 11
      xmlStroller.php

+ 11 - 10
test.php

@@ -2,6 +2,8 @@
 
 require_once(__DIR__.'/xmlStroller.php');
 
+use XmlStroller\XmlStroller as XmlStroller;
+
 class XmlStrollerTester extends PHPUnit_Framework_TestCase
 {
 	public function testLoad()
@@ -23,9 +25,9 @@ class XmlStrollerTester extends PHPUnit_Framework_TestCase
 		$this->assertCount(13, $parser->{"catalog book"});
 		$this->assertCount(13, $parser->{"catalog    book"});
 		$this->assertCount(13, $parser->{"book"});
-		$this->assertContainsOnlyInstancesOf("XmlStroller", $parser->{"catalog book"});
-		$this->assertContainsOnlyInstancesOf("XmlStroller", $parser->{"catalog   book"});
-		$this->assertContainsOnlyInstancesOf("XmlStroller", $parser->{"book"});
+		$this->assertContainsOnlyInstancesOf("\XmlStroller\XmlStroller", $parser->{"catalog book"});
+		$this->assertContainsOnlyInstancesOf("\XmlStroller\XmlStroller", $parser->{"catalog   book"});
+		$this->assertContainsOnlyInstancesOf("\XmlStroller\XmlStroller", $parser->{"book"});
 		$this->assertCount(0, $parser->{"fail"});
 		$this->assertCount(0, $parser->{"catalog fail"});
 		$this->assertCount(0, $parser->{"book fail"});
@@ -45,12 +47,12 @@ class XmlStrollerTester extends PHPUnit_Framework_TestCase
 		$this->assertCount(13, $parser->{"catalog > book"});
 		$this->assertCount(13, $parser->{"catalog   >   book"});
 		$this->assertCount(13, $parser->{" > catalog > book"});
-		$this->assertContainsOnlyInstancesOf("XmlStroller", $parser->{">catalog>book"});
-		$this->assertContainsOnlyInstancesOf("XmlStroller", $parser->{"catalog>book"});
-		$this->assertContainsOnlyInstancesOf("XmlStroller", $parser->{"catalog >book"});
-		$this->assertContainsOnlyInstancesOf("XmlStroller", $parser->{"catalog> book"});
-		$this->assertContainsOnlyInstancesOf("XmlStroller", $parser->{"catalog > book"});
-		$this->assertContainsOnlyInstancesOf("XmlStroller", $parser->{"catalog   >   book"});
+		$this->assertContainsOnlyInstancesOf("\XmlStroller\XmlStroller", $parser->{">catalog>book"});
+		$this->assertContainsOnlyInstancesOf("\XmlStroller\XmlStroller", $parser->{"catalog>book"});
+		$this->assertContainsOnlyInstancesOf("\XmlStroller\XmlStroller", $parser->{"catalog >book"});
+		$this->assertContainsOnlyInstancesOf("\XmlStroller\XmlStroller", $parser->{"catalog> book"});
+		$this->assertContainsOnlyInstancesOf("\XmlStroller\XmlStroller", $parser->{"catalog > book"});
+		$this->assertContainsOnlyInstancesOf("\XmlStroller\XmlStroller", $parser->{"catalog   >   book"});
 		$this->assertCount(0, $parser->{"catalog > fail"});
 		$this->assertCount(0, $parser->{">fail"});
 	}
@@ -81,7 +83,6 @@ class XmlStrollerTester extends PHPUnit_Framework_TestCase
 		$this->assertEquals(39.95, $parser->{"catalog book price[currency=EURO]"}[0]->valueDouble());
 		$book = $parser->{"book price[currency=EURO]"}[0];
 		$book = $book->parent();
-		var_dump($book);
 		try {
 			$parser->{"catalog book[id=]"};
 			$this->fail("Expected Exception");

+ 111 - 0
xmlParser.php

@@ -0,0 +1,111 @@
+<?php
+
+namespace XmlStroller;
+
+class XmlNode implements \Iterator
+{
+	private $itPosition;
+
+	private $xml_name;
+	private $xml_value;
+	private $xml_parent;
+	private $xml_children;
+	private $xml_attributes;
+
+	private function __construct($parent, $name =null)
+	{
+		$this->xml_children = array();
+		$this->xml_name = $name;
+		$this->xml_value = null;
+		$this->xml_parent = $parent;
+		$this->xml_attributes = array();
+		$this->itPosition = 0;
+	}
+
+	private function doParse(&$reader)
+	{
+		while ($reader->read())
+		{
+			if ($reader->nodeType == \XMLReader::ELEMENT)
+			{
+				$i = new self($this, $reader->name);
+				if ($reader->moveToFirstAttribute())
+				{
+					$i->xml_attributes[$reader->name] = $reader->value;
+					while ($reader->moveToNextAttribute())
+						$i->xml_attributes[$reader->name] = $reader->value;
+				}
+				$i->doParse($reader);
+				$this->xml_children[] = $i;
+			}
+			else if ($reader->nodeType == \XMLReader::END_ELEMENT)
+				return;
+			else if ($reader->nodeType == \XMLReader::TEXT)
+				$this->xml_value = $reader->value;
+			else if ($reader->nodeType == \XMLReader::WHITESPACE || $reader->nodeType == \XMLReader::SIGNIFICANT_WHITESPACE)
+				;
+		}
+	}
+
+	public static function parse($data)
+	{
+		$root = new self(null, null);
+		$reader = new \XMLReader();
+		$reader->XML($data);
+		$root->doParse($reader);
+		return $root;
+	}
+
+	public function current()
+	{
+		return $this->xml_children[$this->itPosition];
+	}
+
+	public function key()
+	{
+		return $this->itPosition;
+	}
+
+	public function next()
+	{
+		$this->itPosition++;
+	}
+
+	public function rewind()
+	{
+		$this->itPosition = 0;
+	}
+
+	public function valid()
+	{
+		return isset($this->xml_children[$this->itPosition]);
+	}
+
+	public function getName()
+	{ return $this->xml_name; }
+
+	public function attributes()
+	{ return array_merge($this->xml_attributes); }
+
+	public function __clone()
+	{
+		$r = new self(null, $this->xml_name);
+		$r->xml_value = $this->xml_value;
+		$r->xml_attributes = array_merge($this->xml_attributes);
+		$r->xml_children = array();
+		foreach ($this->xml_children as $j)
+		{
+			$_j = clone($j);
+			$_j->xml_parent = $r;
+			$r->xml_children[] = $_j;
+		}
+		return $r;
+	}
+
+	public function __toString()
+	{ return $this->xml_value == null ? $this->xml_name : $this->xml_value; }
+
+	public function parent()
+	{ return $this->xml_parent; }
+}
+

+ 8 - 11
xmlStroller.php

@@ -1,10 +1,8 @@
 <?php
 
-class XmlNode extends SimpleXmlIterator
-{
-	public function parent()
-	{ return $this->xpath(".."); }
-}
+namespace XmlStroller;
+
+require_once (dirname(__FILE__).'/xmlParser.php');
 
 class XmlStroller
 {
@@ -36,9 +34,9 @@ class XmlStroller
     public function __construct($data)
     {
 		if (is_string($data))
-			$this->xmlNode = new \XmlNode($data);
-		else if ($data instanceof \XmlNode)
-			$this->xmlNode = $data;
+			$this->xmlNode = XmlNode::parse($data);
+		else if ($data instanceof XmlNode)
+			$this->xmlNode = clone ($data);
     }
 
     private function getTokens($str)
@@ -178,7 +176,7 @@ class XmlStroller
                 foreach ($criteria[0][1]["fnc"] as $fnc)
                 {
                     if (!array_key_exists($fnc, $this->fncList))
-                        throw new Exception("Unexpected token '{$fnc}', expected function name");
+                        throw new \Exception("Unexpected token '{$fnc}', expected function name");
                     //TODO check fnc parameters
                     //TODO exec fnc
                 }
@@ -206,10 +204,9 @@ class XmlStroller
     public function select($criteria_str)
     {
         $request = $this->compile($criteria_str);
-		if ($this->debug) { echo "Compiler output: "; var_dump($request); }
         $result = array();
         foreach ($request as $i)
-            $this->checkQuery(array($this->xmlNode), $result, $i);
+            $this->checkQuery($this->xmlNode, $result, $i);
 		$r = array();
 		foreach ($result as $i)
 			$r[] = new self($i);