diff --git a/src/Symfony/Component/VarDumper/Caster/XmlReaderCaster.php b/src/Symfony/Component/VarDumper/Caster/XmlReaderCaster.php new file mode 100644 index 0000000000000..117dcf5394d3d --- /dev/null +++ b/src/Symfony/Component/VarDumper/Caster/XmlReaderCaster.php @@ -0,0 +1,156 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts XmlReader class to array representation. + * + * @author Baptiste Clavié + */ +class XmlReaderCaster +{ + private static $nodeTypes = array( + \XmlReader::NONE => 'NONE', + \XmlReader::ELEMENT => 'ELEMENT', + \XmlReader::ATTRIBUTE => 'ATTRIBUTE', + \XmlReader::TEXT => 'TEXT', + \XmlReader::CDATA => 'CDATA', + \XmlReader::ENTITY_REF => 'ENTITY_REF', + \XmlReader::ENTITY => 'ENTITY', + \XmlReader::PI => 'PI', + \XmlReader::COMMENT => 'COMMENT', + \XmlReader::DOC => 'DOC', + \XmlReader::DOC_TYPE => 'DOC_TYPE', + \XmlReader::DOC_FRAGMENT => 'DOC_FRAGMENT', + \XmlReader::NOTATION => 'NOTATION', + \XmlReader::WHITESPACE => 'WHITESPACE', + \XmlReader::SIGNIFICANT_WHITESPACE => 'SIGNIFICANT_WHITESPACE', + \XmlReader::END_ELEMENT => 'END_ELEMENT', + \XmlReader::END_ENTITY => 'END_ENTITY', + \XmlReader::XML_DECLARATION => 'XML_DECLARATION', + ); + + private static $filteredTypes = array( + \XmlReader::ENTITY_REF => true, + \XmlReader::ENTITY => true, + \XmlReader::PI => true, + \XmlReader::DOC => true, + \XmlReader::DOC_TYPE => true, + \XmlReader::DOC_FRAGMENT => true, + \XmlReader::NOTATION => true, + \XmlReader::WHITESPACE => true, + \XmlReader::SIGNIFICANT_WHITESPACE => true, + \XmlReader::END_ELEMENT => true, + \XmlReader::END_ENTITY => true, + ); + + public static function castXmlReader(\XmlReader $reader, array $a, Stub $stub, $isNested) + { + $nodeType = new ConstStub(self::$nodeTypes[$reader->nodeType], $reader->nodeType); + $parserProperties = new EnumStub(array( + 'LOADDTD' => $reader->getParserProperty(\XmlReader::LOADDTD), + 'DEFAULTATTRS' => $reader->getParserProperty(\XmlReader::DEFAULTATTRS), + 'VALIDATE' => $reader->getParserProperty(\XmlReader::VALIDATE), + 'SUBST_ENTITIES' => $reader->getParserProperty(\XmlReader::SUBST_ENTITIES), + )); + + if (\XmlReader::NONE === $reader->nodeType) { + return $a + self::castXmlNone($nodeType, $parserProperties); + } + + if (\XmlReader::ATTRIBUTE === $reader->nodeType) { + return $a + self::castAttribute($reader, $nodeType, $parserProperties); + } + + $infos = array( + 'localName' => $reader->localName, + 'nodeType' => $nodeType, + 'depth' => $reader->depth, + 'attributeCount' => $reader->attributeCount, + 'hasAttributes' => $reader->hasAttributes, + 'hasValue' => $reader->hasValue, + 'isDefault' => $reader->isDefault, + 'isEmptyElement' => $reader->isEmptyElement, + ); + + if ('' !== $reader->prefix) { + $infos['prefix'] = $reader->prefix; + $infos['namespaceURI'] = $reader->namespaceURI; + } + + if ($reader->hasValue && \XmlReader::TEXT === $reader->nodeType) { + $infos['value'] = $reader->value; + } + + if ($reader->hasAttributes) { + $infos[Caster::PREFIX_VIRTUAL.'attributes'] = array(); + + for ($i = 0; $i < $reader->attributeCount; ++$i) { + $infos[Caster::PREFIX_VIRTUAL.'attributes'][] = $reader->getAttributeNo($i); + } + } + + if (isset(self::$filteredTypes[$reader->nodeType])) { + $infos = self::castFilteredElement($reader, $infos, $stub, $nodeType); + } + + $infos[Caster::PREFIX_VIRTUAL.'parserProperties'] = $parserProperties; + + return $a + $infos; + } + + private static function castXmlNone(ConstStub $type, EnumStub $properties) + { + return array( + 'nodeType' => $type, + Caster::PREFIX_VIRTUAL.'parserProperties' => $properties, + ); + } + + private static function castFilteredElement(\XmlReader $reader, array $infos, Stub $stub, ConstStub $type) + { + $cut = array( + 'localName' => $reader->localName, + 'nodeType' => $type, + 'depth' => $reader->depth, + ); + + $stub->cut += count($infos) - count($cut); + + return $cut; + } + + private static function castAttribute(\XmlReader $reader, ConstStub $type, EnumStub $properties) + { + $infos = array( + 'localName' => $reader->localName, + 'nodeType' => $type, + 'depth' => $reader->depth, + 'isDefault' => $reader->isDefault, + 'hasValue' => $reader->hasValue, + ); + + if ($reader->hasValue) { + $infos['value'] = $reader->value; + } + + if ('' !== $reader->prefix) { + $infos['prefix'] = $reader->prefix; + $infos['namespaceURI'] = $reader->namespaceURI; + } + + $infos[Caster::PREFIX_VIRTUAL.'parserProperties'] = $properties; + + return $infos; + } +} diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 99ca07f264d76..ea1495519547c 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -67,6 +67,8 @@ abstract class AbstractCloner implements ClonerInterface 'DOMProcessingInstruction' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castProcessingInstruction', 'DOMXPath' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castXPath', + 'XmlReader' => 'Symfony\Component\VarDumper\Caster\XmlReaderCaster::castXmlReader', + 'ErrorException' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castErrorException', 'Exception' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castException', 'Error' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castError', diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/XmlReaderCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/XmlReaderCasterTest.php new file mode 100644 index 0000000000000..597878436d85d --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Caster/XmlReaderCasterTest.php @@ -0,0 +1,317 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Tests\Caster; + +use Symfony\Component\VarDumper\Test\VarDumperTestTrait; + +/** + * @author Baptiste Clavié + */ +class XmlReaderCasterTest extends \PHPUnit_Framework_TestCase +{ + use VarDumperTestTrait; + + /** @var \XmlReader */ + private $reader; + + public function setUp() + { + $this->reader = new \XmlReader(); + $this->reader->open(__DIR__.'/../Fixtures/xml_reader.xml'); + } + + public function testSimpleElementNode() + { + $dump = <<<'DUMP' +XMLReader { + +localName: "foo" + +nodeType: ELEMENT + +depth: 0 + +attributeCount: 0 + +hasAttributes: false + +hasValue: false + +isDefault: false + +isEmptyElement: false + parserProperties: { + LOADDTD: false + DEFAULTATTRS: false + VALIDATE: false + SUBST_ENTITIES: false + } +} +DUMP; + + while ($this->reader->read() && $this->reader->nodeType !== \XmlReader::ELEMENT); + + $this->assertDumpEquals($dump, $this->reader); + } + + public function testNestedElement() + { + $dump = <<<'DUMP' +XMLReader { + +localName: "bar" + +nodeType: ELEMENT + +depth: 1 + +attributeCount: 0 + +hasAttributes: false + +hasValue: false + +isDefault: false + +isEmptyElement: false + parserProperties: { + LOADDTD: false + DEFAULTATTRS: false + VALIDATE: false + SUBST_ENTITIES: false + } +} + +DUMP; + + while ($this->reader->read() && $this->reader->localName !== 'bar'); + + $this->assertDumpEquals($dump, $this->reader); + } + + public function testEmptyElement() + { + $dump = <<<'DUMP' +XMLReader { + +localName: "bar" + +nodeType: ELEMENT + +depth: 1 + +attributeCount: 0 + +hasAttributes: false + +hasValue: false + +isDefault: false + +isEmptyElement: true + parserProperties: { + LOADDTD: false + DEFAULTATTRS: false + VALIDATE: false + SUBST_ENTITIES: false + } +} + +DUMP; + + while ($this->reader->read() && $this->reader->localName !== 'bar'); + + $this->reader->next('bar'); + + $this->assertDumpEquals($dump, $this->reader); + } + + public function testElementWithAttributes() + { + $dump = <<<'DUMP' +XMLReader { + +localName: "bar" + +nodeType: ELEMENT + +depth: 1 + +attributeCount: 2 + +hasAttributes: true + +hasValue: false + +isDefault: false + +isEmptyElement: false + attributes: array:2 [ + 0 => "bar" + 1 => "fubar" + ] + parserProperties: { + LOADDTD: false + DEFAULTATTRS: false + VALIDATE: false + SUBST_ENTITIES: false + } +} + +DUMP; + + while ($this->reader->read() && $this->reader->localName !== 'bar'); + + $this->reader->next('bar'); + $this->reader->next('bar'); + $this->reader->next('bar'); + + $this->assertDumpEquals($dump, $this->reader); + } + + public function testTextElement() + { + $dump = <<<'DUMP' +XMLReader { + +localName: "#text" + +nodeType: TEXT + +depth: 2 + +attributeCount: 0 + +hasAttributes: false + +hasValue: true + +isDefault: false + +isEmptyElement: false + +value: "With text" + parserProperties: { + LOADDTD: false + DEFAULTATTRS: false + VALIDATE: false + SUBST_ENTITIES: false + } +} + +DUMP; + + while ($this->reader->read() && $this->reader->nodeType !== \XmlReader::TEXT); + + $this->assertDumpEquals($dump, $this->reader); + } + + /** @dataProvider textFilteredProvider */ + public function testFilteredTextElement($nodeType, $nodeTypeName, $depth, $localName) + { + $dump = <<reader->read() && $this->reader->nodeType !== $nodeType); + + $this->assertDumpEquals($dump, $this->reader); + } + + public function textFilteredProvider() + { + return array( + 'Significant Whiltespace element' => array(\XmlReader::SIGNIFICANT_WHITESPACE, 'SIGNIFICANT_WHITESPACE', 1, '#text'), + ); + } + + /** @dataProvider elementFilteredProvider */ + public function testFilteredElement($localName, $nodeType, $nodeTypeName, $expandType, $depth) + { + $dump = <<reader->read() && $this->reader->nodeType !== $nodeType); + + $this->assertDumpEquals($dump, $this->reader); + } + + public function elementFilteredProvider() + { + return array( + 'End Element' => array('bar', \XmlReader::END_ELEMENT, 'END_ELEMENT', 'DOMElement', 1), + ); + } + + public function testAttributeNode() + { + $dump = <<<'DUMP' +XMLReader { + +localName: "foo" + +nodeType: ATTRIBUTE + +depth: 2 + +isDefault: false + +hasValue: true + +value: "bar" + parserProperties: { + LOADDTD: false + DEFAULTATTRS: false + VALIDATE: false + SUBST_ENTITIES: false + } +} + +DUMP; + + while ($this->reader->read() && !$this->reader->hasAttributes); + + $this->reader->moveToFirstAttribute(); + + $this->assertDumpEquals($dump, $this->reader); + } + + public function testPrefixedElements() + { + $dump = <<<'DUMP' +XMLReader { + +localName: "baz" + +nodeType: ELEMENT + +depth: 2 + +attributeCount: 0 + +hasAttributes: false + +hasValue: false + +isDefault: false + +isEmptyElement: false + +prefix: "baz" + +namespaceURI: "http://symfony.com" + parserProperties: { + LOADDTD: false + DEFAULTATTRS: false + VALIDATE: false + SUBST_ENTITIES: false + } +} +DUMP; + + while ($this->reader->read() && $this->reader->localName !== 'baz'); + + $this->assertDumpEquals($dump, $this->reader); + } + + public function testNone() + { + $dump = <<<'DUMP' +XMLReader { + +nodeType: NONE + parserProperties: { + LOADDTD: false + DEFAULTATTRS: false + VALIDATE: false + SUBST_ENTITIES: false + } +} +DUMP; + + while ($this->reader->read()); + + $this->assertDumpEquals($dump, $this->reader); + } + + public function tearDown() + { + $this->reader->close(); + } +} diff --git a/src/Symfony/Component/VarDumper/Tests/Fixtures/xml_reader.xml b/src/Symfony/Component/VarDumper/Tests/Fixtures/xml_reader.xml new file mode 100644 index 0000000000000..740c399fc4437 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Fixtures/xml_reader.xml @@ -0,0 +1,10 @@ + + + + + With text + + + + +