preserveWhiteSpace = false; // attach kml and Document tag $e_kml = $doc->createElementNS("http://earth.google.com/kml/2.2", "kml"); $e_document = $doc->createElement("Document"); $e_kml->appendChild($e_document); $doc->appendChild($e_kml); // attach placemarks $e = new mb_notice("to string: #placemarks: " . count($this->placemarkArray)); $lineStyleNode = $doc->createElement("Style"); $lineStyleNode->setAttribute("id", "linestyleExample"); $lineStyleColorNode = $doc->createElement("color", "7f0000ff"); $lineStyleWidthNode = $doc->createElement("width", 4); $lineStyleNode->appendChild($lineStyleColorNode); $lineStyleNode->appendChild($lineStyleWidthNode); $e_document->appendChild($lineStyleNode); // // line segments first // $coordinates = ""; for ($i = 0; $i < count($this->placemarkArray); $i++) { $currentPlacemark = $this->placemarkArray[$i]; $e = new mb_notice("now: " . $i . " of " . (count($this->placemarkArray)-1) . " (is a " . get_class($currentPlacemark) . ")"); switch ($currentPlacemark->getGeometryType()) { case "KMLLine" : $coordinatesArray = $currentPlacemark->getGeometry()->getPointArray(); for ($j = 0; $j < count($coordinatesArray); $j++) { if (!($j == 0 && $i == 0)) { $coordinates .= " "; } $coordinates .= $coordinatesArray[$j]["x"] . "," . $coordinatesArray[$j]["y"] . "," . $coordinatesArray[$j]["z"]; } break; } } // create a placemark tag with a geometry and add it to the document $e_coordinates = $doc->createElement("coordinates", $coordinates); $e_geometry = $doc->createElement("LineString"); $e_geometry->appendChild($e_coordinates); $e_placemark = $doc->createElement("Placemark"); $e_placemark->appendChild($e_geometry); $e_pl_name = $doc->createElement("name", "Route"); $e_placemark->appendChild($e_pl_name); $e_pl_style = $doc->createElement("styleUrl", "#linestyleExample"); $e_placemark->appendChild($e_pl_style); $e_document->appendChild($e_placemark); /* // // now pois // // attach placemarks $e = new mb_notice("to string: #placemarks: " . count($this->placemarkArray)); for ($i = 0; $i < count($this->placemarkArray); $i++) { $currentPlacemark = $this->placemarkArray[$i]; $e = new mb_notice("now: " . $i . " of " . (count($this->placemarkArray)-1) . " (is a " . get_class($currentPlacemark) . ")"); $pl_instructions = $currentPlacemark->getProperty("instruction"); $pl_name_array = array(); $pl_name = false; $pl_description = false; if ($pl_instructions != null) { $pl_name_array = explode("|", $pl_instructions); } switch ($currentPlacemark->getGeometryType()) { case "KMLPoint" : if (count($pl_name_array) > 2) { $pl_name = $pl_name_array[0]; $pl_description = $pl_name_array[1]; } $e_geometry = $doc->createElement("Point"); $point = $currentPlacemark->getGeometry()->getPoint(); $coordinates = $point["x"] . "," . $point["y"]; $e_coordinates = $doc->createElement("coordinates", $coordinates); $e_geometry->appendChild($e_coordinates); break; } // create a placemark tag with a geometry and add it to the document if ($e_geometry) { $e_placemark = $doc->createElement("Placemark"); $e_placemark->appendChild($e_geometry); if ($pl_name) { $e_pl_name = $doc->createElement("name", $pl_name); $e_placemark->appendChild($e_pl_name); } if ($pl_description) { $e_pl_description = $doc->createElement("description", $pl_description); $e_placemark->appendChild($e_pl_description); } $e_document->appendChild($e_placemark); } } */ return $doc->saveXML(); } /** * @return string the KML document. */ public function __toString() { if (!$this->kml) { //KML 2.2 output $doc = new DOMDocument("1.0", CHARSET); $doc->preserveWhiteSpace = false; // attach kml and Document tag $e_kml = $doc->createElementNS("http://earth.google.com/kml/2.2", "kml"); $e_document = $doc->createElement("Document"); $e_kml->appendChild($e_document); $doc->appendChild($e_kml); // attach placemarks $e = new mb_notice("to string: #placemarks: " . count($this->placemarkArray)); for ($i = 0; $i < count($this->placemarkArray); $i++) { $currentPlacemark = $this->placemarkArray[$i]; $e = new mb_notice("now: " . $i . " of " . (count($this->placemarkArray)-1) . " (is a " . get_class($currentPlacemark) . ")"); $pl_instructions = $currentPlacemark->getProperty("instruction"); $pl_name_array = array(); $pl_name = false; $pl_description = false; if ($pl_instructions != null) { $pl_name_array = explode("|", $pl_instructions); } switch ($currentPlacemark->getGeometryType()) { case "KMLPoint" : if (count($pl_name_array) > 2) { $pl_name = $pl_name_array[0]; $pl_description = $pl_name_array[1]; } $e_geometry = $doc->createElement("Point"); $point = $currentPlacemark->getGeometry()->getPoint(); $coordinates = $point["x"] . "," . $point["y"]; $e_coordinates = $doc->createElement("coordinates", $coordinates); $e_geometry->appendChild($e_coordinates); break; /* TODO:Polygons case "KMLPolygon" : $e_geometry = $doc->createElement("Polygon"); $e_outer = $doc->createElement("OuterBoundaryIs"); $e_outer_lr = $doc->createElement("LinearRing"); $outer_coordinates = ""; // TODO: get coords from placemark $e_outer_coordinates = $doc->createElement("Coordinates", $outer_coordinates); $e_outer_lr->appendChild($e_outer_coordinates); $e_outer->appendChild($e_outer_lr); for ($j = 0; $j < $currentPlacemark; $j++) { } $e_geometry->appendChild($e_coordinates); outerBoundaryIs"}->{"LinearRing"}->{"coordinates break; */ case "KMLLine" : if (count($pl_name_array) > 2) { $pl_description = $pl_name_array[1]; } $e_geometry = $doc->createElement("LineString"); $coordinatesArray = $currentPlacemark->getGeometry()->getPointArray(); $coordinates = ""; for ($j = 0; $j < count($coordinatesArray); $j++) { if ($j > 0) { $coordinates .= " "; } $coordinates .= $coordinatesArray[$j]["x"] . "," . $coordinatesArray[$j]["y"] . "," . $coordinatesArray[$j]["z"]; } $e_coordinates = $doc->createElement("coordinates", $coordinates); $e_geometry->appendChild($e_coordinates); break; /* TODO: Multigeometries case "KMLMultiGeometry" : break; */ } // create a placemark tag with a geometry and add it to the document if ($e_geometry) { $e_placemark = $doc->createElement("Placemark"); $e_placemark->appendChild($e_geometry); if ($pl_name) { $e_pl_name = $doc->createElement("name", $pl_name); $e_placemark->appendChild($e_pl_name); } if ($pl_description) { $e_pl_description = $doc->createElement("description", $pl_description); $e_placemark->appendChild($e_pl_description); } $e_document->appendChild($e_placemark); } } $this->kml = $doc->saveXML(); } return $this->kml; } /** * @return string the ID of this KML. */ public function getId () { return $this->id; } /** * parses an incoming KML, creates the object, * stores the kml in the object and in the database. * * @param string a KML document. * @return boolean true if the parsing succeded, else false. */ public function parseKml ($kml) { $this->kml = $kml; if (!$this->storeInDb()) { return false; } $parser = new KmlOwsParser(); $parser->parseKML($kml, $this->id); $this->placemarkArray = $parser->placemarkArray; return true; } /** * parses an incoming GeoJSON, creates the object, * stores the kml in the object and in the database. * * @param string a geoJSON. * @return boolean true if the parsing succeded, else false. */ public function parseGeoJSON ($geoJSON) { $this->kml = ""; if (!$this->storeInDb()) { return false; } $parser = new KmlOwsParser(); $parser->parseGeoJSON($geoJSON, $this->id); $e = new mb_notice("parsing finished...#placemarks: " . count($this->placemarkArray) . " (" . count($parser->placemarkArray) . ")"); $this->placemarkArray = $parser->placemarkArray; // print_r($this); // $this->kml = $this->__toString(); // $this->updateInDb($this->kml, $this->id); return true; } /** * @return string the geoJSON representation of the KML. */ public function toGeoJSON() { $str = ""; $numberOfPlacemarks = count($this->placemarkArray); if ($numberOfPlacemarks > 0) { $str .= "{\"type\": \"FeatureCollection\", \"features\": ["; for ($i=0; $i < $numberOfPlacemarks; $i++) { if ($i > 0) { $str .= ","; } $str .= $this->placemarkArray[$i]->toGeoJSON(); } $str .= "]}"; } else { $e = new mb_exception("KML: toGeoJSON: this placemarkArray is empty!"); } return $str; } private function updateInDb($kmlDoc, $kmlId) { $sql = "UPDATE gui_kml SET kml_doc = $1 WHERE kml_id = $2"; $v = array($kmlDoc, $kmlId); $t = array("s", "i"); $result = db_prep_query($sql, $v, $t); if (!$result) { $e = new mb_exception("class_kml: kml update failed! " . db_error()); return false; } } public function updateKml ($kmlId, $placemarkId, $geoJSON) { $kmlFromDb = $this->getKmlDocumentFromDB($kmlId); if ($kmlFromDb !== NULL) { // load the KML from the database in the DOM object $kmlDoc_DOM = new DOMDocument("1.0"); $kmlDoc_DOM->encoding = CHARSET; $kmlDoc_DOM->preserveWhiteSpace = false; $kmlDoc_DOM->loadXML($kmlFromDb); //load the geoJSON $json = new Mapbender_JSON(); $geoObj = $json->decode($geoJSON); // construct an array that holds all metadata of the placemark $metadataObj = $geoObj->properties; // construct an array that holds all geometries of the placemark $geometryObj = $geoObj->geometry; $geometryType = $geometryObj->type; if ($geometryType == "GeometryCollection") { $geometryArray = $geometryObj->geometries; } else if ($geometryType == "Point" || $geometryType == "LineString" || $geometryType == "Polygon") { $geometryArray = array($geometryObj); } else { $e = new mb_exception("class_kml: Invalid geometry type " . $geometryType); return false; } // // apply the changes // $currentPlacemarkArray = $kmlDoc_DOM->getElementsByTagName("Placemark"); $currentPlacemark = $currentPlacemarkArray->item($placemarkId); if ($currentPlacemark) { $metadataUpdateSuccessful = $this->updateMetadata($currentPlacemark, $metadataObj); $geometryUpdateSuccessful = $this->updateGeometries($currentPlacemark, $geometryArray); } else { $e = new mb_exception("class_kml.php: updateKml: placemark " . $placemarkId . " not found in KML " . $kmlId . "."); return false; } if ($metadataUpdateSuccessful && $geometryUpdateSuccessful) { $updatedKml = $kmlDoc_DOM->saveXML(); $this->updateInDb($updatedKml, $kmlId); } else { if (!$metadataUpdateSuccessful) { $e = new mb_exception("class_kml: Updating the metadata failed, no database update."); } if (!$geometryUpdateSuccessful) { $e = new mb_exception("class_kml: Updating the geometries failed, no database update."); } return false; } } else { $e = new mb_exception("class_kml: No KML found in database, no database update. " . db_error()); return false; } return true; } // // // ------------------------------- private ----------------------------------------------- // // /** * Store this KML in the database, and sets the ID. * * @return boolean true, if the KML could be stored in the database; else false. */ private function storeInDb () { if ($_SESSION["mb_user_id"] && $_SESSION["mb_user_gui"]) { $con = db_connect(DBSERVER,OWNER,PW); db_select_db(DB,$con); $sql = "INSERT INTO gui_kml "; $sql .= "(fkey_mb_user_id, fkey_gui_id, kml_doc, kml_name, kml_description, kml_timestamp) "; $sql .= "VALUES "; $sql .= "($1, $2, $3, $4, $5, $6)"; $v = array ($_SESSION["mb_user_id"], $_SESSION["mb_user_gui"], $this->kml, "name", "description", time()); $t = array ("i", "s", "s", "s", "s", "s"); $res = db_prep_query($sql, $v, $t); if (!$res) { $e = new mb_exception("class_kml.php: storeInDb: failed to store KML in database: " . db_error()); return false; } $this->id = db_insert_id($con, "gui_kml", "kml_id"); return true; } else { // should be false, but code in caller has to be changed first. return true; } } /** * @param integer the ID of the KML. * @return string the KML document with the given ID. */ public function getKmlDocumentFromDB ($kmlId) { $con = db_connect(DBSERVER,OWNER,PW); db_select_db(DB,$con); //get KML from database (check if user is allowed to access) # for now, do not restrict access # $sql = "SELECT kml_doc FROM gui_kml WHERE kml_id = $1 AND fkey_mb_user_id = $2 AND fkey_gui_id = $3 LIMIT 1"; # $v = array($kmlId, $_SESSION["mb_user_id"], $_SESSION["mb_user_gui"]); # $t = array("i", "i", "s"); $sql = "SELECT kml_doc FROM gui_kml WHERE kml_id = $1 LIMIT 1"; $v = array($kmlId); $t = array("i"); $result = db_prep_query($sql, $v, $t); $row = db_fetch_array($result); if ($row) { return $row["kml_doc"]; } else { $e = new mb_exception("class_kml.php: getKMLDocumentFromDB: no KML found for ID " . $kmlId); } return ""; } /** * @param string the tag name. * @return string the tag name without its namespace. */ private function sepNameSpace($s){ $c = mb_strpos($s, ":"); if ($c > 0) { $s = mb_substr($s, $c+1); } return $s; } private function updateGeometries($currentPlacemark, $geometryArray) { $cnt = 0; $childNodes = $currentPlacemark->childNodes; foreach ($childNodes as $childNode) { $name = $childNode->nodeName; if ( in_array($name, array("Point","LineString","Polygon"))) { $returnValue = $this->updateGeometry($childNode, $geometryArray[$cnt]); if (!$returnValue) { return false; } $cnt ++; } else if ($name == "MultiGeometry") { return $this->updateGeometries($childNode, $geometryArray); } } return true; } private function updateGeometry ($currentNode, $geometry) { $json = new Mapbender_JSON(); $currentNode_SimpleXML = simplexml_import_dom($currentNode); $currentTypeXml = mb_strtoupper($currentNode->nodeName); $currentTypeGeoJson = mb_strtoupper($geometry->type); if ($currentTypeGeoJson != $currentTypeXml) { $e = new mb_exception("class_kml: geometry type mismatch: geoJSON: " . $currentTypeGeoJson . "; XML: " . $currentTypeXml); return false; } if ($currentTypeXml == "POLYGON") { // GML 3 $gmlNode = $currentNode_SimpleXML->{"exterior"}->{"LinearRing"}->{"posList"}; $kmlNode = $currentNode_SimpleXML->{"outerBoundaryIs"}->{"LinearRing"}->{"coordinates"}; if ($gmlNode && $gmlNode->asXML()) { $currentNode_SimpleXML->{"exterior"}->{"LinearRing"}->{"posList"} = preg_replace("/,/", " ", preg_replace("/\[|\]/", "", $json->encode($geometry->coordinates))); } // KML 2.2 else if ($kmlNode && $kmlNode->asXML()) { $currentNode_SimpleXML->{"outerBoundaryIs"}->{"LinearRing"}->{"coordinates"} = preg_replace("/\],/", " ", preg_replace("/\][^,]|\[/", "", $json->encode($geometry->coordinates))); } } elseif ($currentTypeXml == "POINT") { $gmlNode = $currentNode_SimpleXML->{"pos"}; $kmlNode = $currentNode_SimpleXML->{"coordinates"}; // GML 3 if ($gmlNode && $gmlNode->asXML()) { $currentNode_SimpleXML->{"pos"} = preg_replace("/,/", " ", preg_replace("/\[|\]/", "", $json->encode($geometry->coordinates))); } // KML 2.2 else if ($kmlNode && $kmlNode->asXML()) { $currentNode_SimpleXML->{"coordinates"} = preg_replace("/\[|\]/", "", $json->encode($geometry->coordinates)); } } elseif ($currentTypeXml == "LINESTRING") { $gmlNode = $currentNode_SimpleXML->{"posList"}; $kmlNode = $currentNode_SimpleXML->{"coordinates"}; // GML 3 if ($gmlNode && $gmlNode->asXML()) { $currentNode_SimpleXML->{"posList"} = preg_replace("/,/", " ", preg_replace("/\[|\]/", "", $json->encode($geometry->coordinates))); } // KML 2.2 else if ($kmlNode && $kmlNode->asXML()) { $currentNode_SimpleXML->{"coordinates"} = preg_replace("/\[|\]/", "", $json->encode($geometry->coordinates)); } } return true; } private function updateMetadata($currentPlacemark, $metadataObj) { $metadataExistsAndUpdateSucceeded = true; $currentPlacemark_SimpleXML = simplexml_import_dom($currentPlacemark); $extendedDataNode = $currentPlacemark_SimpleXML->{"ExtendedData"}; if ($extendedDataNode) { $metadataExistsAndUpdateSucceeded = false; // Either, data is within a SCHEMADATA tag... $simpleDataNodes = $extendedDataNode->{"SchemaData"}->{"SimpleData"}; if ($simpleDataNodes) { foreach ($simpleDataNodes as $simpleDataNode) { $tmp = dom_import_simplexml($simpleDataNode); $name = $tmp->getAttribute("name"); // if there is a metadata entry, update it if (isset($metadataObj->$name)) { $tmp->nodeValue = $metadataObj->$name; } } $metadataExistsAndUpdateSucceeded = true; } // ...or within a DATA tag $dataNodes = $extendedDataNode->{"Data"}; if ($dataNodes && !$metadataExistsAndUpdateSucceeded) { foreach ($dataNodes as $dataNode) { $tmp = dom_import_simplexml($dataNode); $name = $tmp->getAttribute("name"); // if there is a metadata entry, update it if (isset($metadataObj->$name)) { $tmp->nodeValue = $metadataObj->$name; } } $metadataExistsAndUpdateSucceeded = true; } } return $metadataExistsAndUpdateSucceeded; } /** * The KML document. */ private $kml; /** * The ID of this KML in the database. */ private $id; /** * An array of {@link KMLPlacemark} */ private $placemarkArray = array(); } ?>