/** {@inheritdoc} */ public function parse($xmlString) { if ($this->validateResponse) { XmlChecker::validXml($xmlString); } $result = xmlrpc_decode($xmlString, 'UTF-8'); $toBeVisited = [&$result]; while (isset($toBeVisited[0]) && ($value =& $toBeVisited[0])) { $type = gettype($value); if ($type === 'object') { $xmlRpcType = $value->{'xmlrpc_type'}; if ($xmlRpcType === 'datetime') { $value = DateTime::createFromFormat('Ymd\\TH:i:s', $value->scalar, isset($timezone) ? $timezone : ($timezone = new DateTimeZone('UTC'))); } elseif ($xmlRpcType === 'base64') { if ($value->scalar !== '') { $value = Base64::serialize($value->scalar); } else { $value = null; } } } elseif ($type === 'array') { foreach ($value as &$element) { $toBeVisited[] =& $element; } } array_shift($toBeVisited); } if (is_array($result)) { reset($result); if (xmlrpc_is_fault($result)) { throw FaultException::fault($result); } } return $result; }
/** {@inheritdoc} */ public function parse($xmlString) { if ($this->validateResponse) { XmlChecker::validXml($xmlString); } $useErrors = libxml_use_internal_errors(true); $xml = new XMLReader(); $xml->xml($xmlString, 'UTF-8', LIBXML_COMPACT | LIBXML_NOCDATA | LIBXML_NOBLANKS | LIBXML_PARSEHUGE); $xml->setParserProperty(XMLReader::VALIDATE, false); $xml->setParserProperty(XMLReader::LOADDTD, false); // This following assignments are auto-generated using fXmlRpc\CodeGenerator\XmlReaderParserBitmaskGenerator // Don’t edit manually static $flagmethodResponse = 0b1; static $flagparams = 0b10; static $flagfault = 0b100; static $flagparam = 0b1000; static $flagvalue = 0b10000; static $flagarray = 0b100000; static $flagmember = 0b1000000; static $flagname = 0b10000000; ${'flag#text'} = 0b100000000; static $flagstring = 0b1000000000; static $flagstruct = 0b10000000000; static $flagint = 0b100000000000; static $flagbiginteger = 0b1000000000000; static $flagi8 = 0b10000000000000; static $flagi4 = 0b100000000000000; static $flagi2 = 0b1000000000000000; static $flagi1 = 0b10000000000000000; static $flagboolean = 0b100000000000000000; static $flagdouble = 0b1000000000000000000; static $flagfloat = 0b10000000000000000000; static $flagbigdecimal = 0b100000000000000000000; ${'flagdateTime.iso8601'} = 0b1000000000000000000000; static $flagdateTime = 0b10000000000000000000000; static $flagbase64 = 0b100000000000000000000000; static $flagnil = 0b1000000000000000000000000; static $flagdom = 0b10000000000000000000000000; static $flagdata = 0b100000000000000000000000000; // End of auto-generated code $aggregates = []; $depth = 0; $nextExpectedElements = 0b1; $i = 0; $isFault = false; while ($xml->read()) { $i++; $nodeType = $xml->nodeType; if ($nodeType === XMLReader::COMMENT || $nodeType === XMLReader::DOC_TYPE || $nodeType === XMLReader::SIGNIFICANT_WHITESPACE && ($nextExpectedElements & 0b100000000) !== 0b100000000) { continue; } if ($nodeType === XMLReader::ENTITY_REF) { libxml_use_internal_errors($useErrors); return ''; } $tagName = $xml->localName; if ($nextExpectedElements !== null && ($flag = isset(${'flag' . $tagName}) ? ${'flag' . $tagName} : -1) && ($nextExpectedElements & $flag) !== $flag) { libxml_use_internal_errors($useErrors); throw ParserException::unexpectedTag($tagName, $nextExpectedElements, get_defined_vars(), $xml->depth, $xml->readOuterXml()); } processing: switch ($nodeType) { case XMLReader::ELEMENT: switch ($tagName) { case 'methodResponse': // Next: params, fault $nextExpectedElements = 0b110; break; case 'params': // Next: param $nextExpectedElements = 0b1000; $aggregates[$depth] = []; $isFault = false; break; case 'fault': $isFault = true; // Break intentionally omitted // Break intentionally omitted case 'param': // Next: value $nextExpectedElements = 0b10000; break; case 'array': $aggregates[++$depth] = []; // Break intentionally omitted // Break intentionally omitted case 'data': // Next: array, data, value $nextExpectedElements = 0b100000000000000000000110000; break; case 'struct': // Next: struct, member, value $nextExpectedElements = 0b10001010000; $aggregates[++$depth] = []; break; case 'member': // Next: name, value $nextExpectedElements = 0b10010000; $aggregates[++$depth] = []; break; case 'name': // Next: #text $nextExpectedElements = 0b100000000; $type = 'name'; break; case 'value': $nextExpectedElements = 0b11111111111111111100110000; $type = 'value'; $aggregates[$depth + 1] = ''; break; case 'base64': case 'string': case 'biginteger': case 'i8': case 'dateTime.iso8601': case 'dateTime': // Next: value, $tagName, #text $nextExpectedElements = 0b100010000 | ${'flag' . $tagName}; $type = $tagName; $aggregates[$depth + 1] = ''; break; case 'nil': // Next: value, $tagName $nextExpectedElements = 0b1000000000000000000010000 | ${'flag' . $tagName}; $type = $tagName; $aggregates[$depth + 1] = null; break; case 'int': case 'i4': case 'i2': case 'i1': // Next: value, #text, $tagName $nextExpectedElements = 0b100010000 | ${'flag' . $tagName}; $type = $tagName; $aggregates[$depth + 1] = 0; break; case 'boolean': // Next: value, #text, $tagName $nextExpectedElements = 0b100010000 | ${'flag' . $tagName}; $type = 'boolean'; $aggregates[$depth + 1] = false; break; case 'double': case 'float': case 'bigdecimal': // Next: value, #text, $tagName $nextExpectedElements = 0b100010000 | ${'flag' . $tagName}; $type = $tagName; $aggregates[$depth + 1] = 0.0; break; case 'dom': $type = 'dom'; // Disable type checking $nextExpectedElements = null; $aggregates[$depth + 1] = $xml->readInnerXml(); break; } break; case XMLReader::END_ELEMENT: switch ($tagName) { case 'params': case 'fault': break 3; case 'param': // Next: params, param $nextExpectedElements = 0b1010; break; case 'value': $nextExpectedElements = 0b100100000011100100011011100; $aggregates[$depth][] = $aggregates[$depth + 1]; break; case 'array': case 'struct': --$depth; // Break intentionally omitted // Break intentionally omitted case 'string': case 'int': case 'biginteger': case 'i8': case 'i4': case 'i2': case 'i1': case 'boolean': case 'double': case 'float': case 'bigdecimal': case 'dateTime.iso8601': case 'dateTime': case 'base64': case 'nil': // Next: value $nextExpectedElements = 0b10000; break; case 'data': // Next: array $nextExpectedElements = 0b100000; break; case 'name': // Next: value, member $nextExpectedElements = 0b1010000; $aggregates[$depth]['name'] = $aggregates[$depth + 1]; break; case 'member': // Next: struct, member $nextExpectedElements = 0b10001000000; $aggregates[$depth - 1][$aggregates[$depth]['name']] = $aggregates[$depth][0]; unset($aggregates[$depth], $aggregates[$depth + 1]); --$depth; break; } break; case XMLReader::TEXT: case XMLReader::SIGNIFICANT_WHITESPACE: switch ($type) { case 'int': case 'i4': case 'i2': case 'i1': $value = (int) $xml->value; break; case 'boolean': $value = $xml->value === '1'; break; case 'double': case 'float': case 'bigdecimal': $value = (double) $xml->value; break; case 'dateTime.iso8601': $value = DateTime::createFromFormat('Ymd\\TH:i:s', $xml->value, isset($timezone) ? $timezone : ($timezone = new DateTimeZone('UTC'))); break; case 'dateTime': $value = DateTime::createFromFormat('Y-m-d\\TH:i:s.uP', $xml->value, isset($timezone) ? $timezone : ($timezone = new DateTimeZone('UTC'))); break; case 'base64': $value = Base64::deserialize($xml->value); break; case 'dom': $doc = new DOMDocument('1.0', 'UTF-8'); $doc->loadXML($aggregates[$depth + 1]); $value = $doc; break; default: $value =& $xml->value; break; } $aggregates[$depth + 1] = $value; if ($nextExpectedElements === null) { break; } // Next: any $nextExpectedElements = 0b111111111111111111111111111; break; } if ($xml->isEmptyElement && $nodeType !== XMLReader::END_ELEMENT) { $nodeType = XMLReader::END_ELEMENT; goto processing; } } libxml_use_internal_errors($useErrors); $result = $aggregates ? array_pop($aggregates[0]) : null; if ($isFault) { throw FaultException::fault($result); } return $result; }