/** * Process XML with the annotated methods of the given class * * @param xml.XPath XPath Instance of xml.XPath * @param php.DomNode Context The XML node to recurse from * @param string classname Fully qualified class name */ public static function recurse($XPath, $Context, $classname) { if (DIA_UNM_DEBUG) { Console::writeLine('recurse: ' . $Context->tagname() . "-> {$classname}"); } $Class = XPClass::forName($classname); $Instance = $Class->newInstance(); if (DIA_UNM_DEBUG) { Console::writeLine('Instance: ' . $Instance->getClassName()); } // loop over class methods with annotation 'fromDia' $methods = $Class->getMethods(); foreach (array_keys($methods) as $key) { $Method = $methods[$key]; if (!$Method->hasAnnotation('fromDia', 'xpath')) { continue; } $name = $Method->getName(); $xpath = $Method->getAnnotation('fromDia', 'xpath'); if (DIA_UNM_DEBUG) { Console::writeLine("--> Method: {$name} Xpath: {$xpath}"); } // continue if this fails: some expressions don't work on WRONG nodes... try { $result = $XPath->query($xpath, $Context); } catch (Exception $e) { if (DIA_UNM_DEBUG) { $e->printStackTrace(); } $nodename = $Context->tagname(); if ($Context->has_attribute('type')) { $type = $Context->get_attribute('type'); } else { $type = '<unknown>'; } if (DIA_UNM_DEBUG) { Console::writeLine("Warn: XPath= '{$xpath}' failed on Node= '{$nodename}' Type= '{$type}'"); } // skip this method/expression continue; } if (DIA_UNM_DEBUG) { Console::writeLine(' + Size of nodeset: ' . sizeof($result->nodeset)); } // loop over nodeset foreach (array_keys($result->nodeset) as $key) { $Node = $result->nodeset[$key]; // key 'value' (simple value) if ($Method->hasAnnotation('fromDia', 'value')) { $type = $Method->getAnnotation('fromDia', 'value'); if (DIA_UNM_DEBUG) { Console::writeLine(" + Value-type: '{$type}'"); } // get node value depending on nod type if (is('domattribute', $Node)) { $nodevalue = $Node->value(); } elseif (is('domelement', $Node)) { // remove whitespace and leading/trailing '#' character $content = $Node->get_content(); if (isset($content) and $content !== '') { $nodevalue = substr(trim($Node->get_content()), 1, -1); } else { $nodevalue = ''; } } elseif (is('domnamespace', $Node)) { $nodevalue = array($Node->prefix() => $Node->namespace_uri()); } else { Console::writeLine('Unknown node class: ' . xp::stringOf($Node)); exit(-1); } switch ($type) { case 'namespace': if (!is_array($nodevalue) or empty($nodevalue)) { Console::writeLine("Nodevalue is no array or is empty: {$nodevalue}"); } $value = $nodevalue; break; case 'enum': case 'int': $nodevalue = cast($nodevalue, 'int'); if (!is_int($nodevalue)) { Console::writeLine("Nodevalue is no integer: {$nodevalue}"); } $value = $nodevalue; break; case 'real': $nodevalue = cast($nodevalue, 'float'); if (!is_real($nodevalue) and !is_int($nodevalue)) { Console::writeLine("Nodevalue is no float/integer: {$nodevalue}"); } $value = $nodevalue; break; case 'string': $nodevalue = cast($nodevalue, 'string'); if (!is_string($nodevalue)) { Console::writeLine("Nodevalue is no string: {$nodevalue}"); } $value = $nodevalue; break; case 'boolean': $value = NULL; if ($nodevalue === 'false') { $value = FALSE; } if ($nodevalue === 'true') { $value = TRUE; } if (!is_bool($value)) { Console::writeLine("Nodevalue is no boolean: {$nodevalue}"); } break; case 'point': case 'array': // comma separated list of values $value = explode(',', $nodevalue); break; case 'rectangle': case 'arrayarray': // semicolon and comma separated list of values $points = explode(';', $nodevalue); $value = array(); foreach ($points as $point) { $value[] = explode(',', $point); } break; case 'font': if (is('domelement', $Node)) { $value = array(); $value['family'] = $Node->get_attribute('family'); $value['style'] = $Node->get_attribute('style'); $value['name'] = $Node->get_attribute('name'); } else { Console::writeLine('Wrong font node: ' . xp::stringOf($Node)); exit(-1); } break; default: Console::writeLine("!!!Unknown 'value' type: '{$type}'!"); } $Method->invoke($Instance, array($value)); } // key 'class' if ($Method->hasAnnotation('fromDia', 'class')) { $classname = $Method->getAnnotation('fromDia', 'class'); if (DIA_UNM_DEBUG) { Console::writeLine(" + Class: {$classname}"); } // recurse with given classname $Obj = DiaUnmarshaller::recurse($XPath, $Node, $classname); // hand results over to the method $Method->invoke($Instance, array($Obj)); } } } return $Instance; }