コード例 #1
0
ファイル: utils.php プロジェクト: geofac/mapguide-rest
 public static function FormatException($app, $type, $errorMessage, $details, $phpTrace, $status = 500, $mimeType = MgMimeType::Html)
 {
     $errResponse = "";
     if ($app->config("Error.OutputStackTrace") === false) {
         if ($mimeType === MgMimeType::Xml || $mimeType == MgMimeType::Kml) {
             $errResponse = sprintf("<?xml version=\"1.0\"?><Error><Type>%s</Type><Message>%s</Message><Details>%s</Details></Error>", MgUtils::EscapeXmlChars($type), MgUtils::EscapeXmlChars($errorMessage), MgUtils::EscapeXmlChars($details));
         } else {
             if ($mimeType === MgMimeType::Json) {
                 $errResponse = sprintf("{ \"Type\": \"%s\", \"Message\": \"%s\", \"Details\": \"%s\" }", MgUtils::EscapeJsonString($type), MgUtils::EscapeJsonString($errorMessage), MgUtils::EscapeJsonString($details));
             } else {
                 $errResponse = sprintf("<html><head><title>%s</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><style>body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana,sans-serif;}h1{margin:0;font-size:48px;font-weight:normal;line-height:48px;}strong{display:inline-block;width:65px;}</style></head><body><h2>%s</h2>%s</body></html>", $type, $errorMessage, $details);
             }
         }
     } else {
         if ($mimeType === MgMimeType::Xml || $mimeType == MgMimeType::Kml) {
             $errResponse = sprintf("<?xml version=\"1.0\"?><Error><Type>%s</Type><Message>%s</Message><Details>%s</Details><StackTrace>%s</StackTrace></Error>", MgUtils::EscapeXmlChars($type), MgUtils::EscapeXmlChars($errorMessage), MgUtils::EscapeXmlChars($details), MgUtils::EscapeXmlChars($phpTrace));
         } else {
             if ($mimeType === MgMimeType::Json) {
                 $errResponse = sprintf("{ \"Type\": \"%s\", \"Message\": \"%s\", \"Details\": \"%s\", \"StackTrace\": \"%s\" }", MgUtils::EscapeJsonString($type), MgUtils::EscapeJsonString($errorMessage), MgUtils::EscapeJsonString($details), MgUtils::EscapeJsonString($phpTrace));
             } else {
                 $errResponse = sprintf("<html><head><title>%s</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><style>body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana,sans-serif;}h1{margin:0;font-size:48px;font-weight:normal;line-height:48px;}strong{display:inline-block;width:65px;}</style></head><body><h2>%s</h2>%s<h2>%s</h2><pre>%s</pre></body></html>", $type, $errorMessage, $details, $app->localizer->getText("L_STACK_TRACE"), $phpTrace);
             }
         }
     }
     return $errResponse;
 }
コード例 #2
0
ファイル: boxedvalue.php プロジェクト: geofac/mapguide-rest
 private static function BoxValue($value, $type, $fmt = "xml")
 {
     $resp = "";
     if ($fmt == "xml") {
         $resp .= '<?xml version="1.0" encoding="utf-8"?>';
         $resp .= "<PrimitiveValue>";
         $resp .= "<Type>{$type}</Type>";
         if ($type == "String") {
             $resp .= "<Value>" . MgUtils::EscapeXmlChars($value) . "</Value>";
         } else {
             $resp .= "<Value>{$value}</Value>";
         }
         $resp .= "</PrimitiveValue>";
     } else {
         //json
         $val = $value;
         if ($type == "String") {
             $val = '"' . MgUtils::EscapeJsonString($val) . '"';
         }
         $resp = '{"PrimitiveValue":{"Type":"' . $type . '","Value":' . $val . '}}';
     }
     return $resp;
 }
コード例 #3
0
 public function SelectAggregates($resId, $schemaName, $className, $type, $format)
 {
     //Check for unsupported representations
     $fmt = $this->ValidateRepresentation($format, array("xml", "json"));
     $mimeType = $this->GetMimeTypeForFormat($fmt);
     try {
         $aggType = $this->ValidateValueInDomain($type, array("count", "bbox", "distinctvalues"), $this->GetMimeTypeForFormat($format));
         $distinctPropName = $this->GetRequestParameter("property", "");
         if ($aggType === "distinctvalues" && $distinctPropName === "") {
             $this->BadRequest($this->app->localizer->getText("E_MISSING_REQUIRED_PARAMETER", "property"), $this->GetMimeTypeForFormat($format));
         }
         $sessionId = "";
         if ($resId->GetRepositoryType() == MgRepositoryType::Session) {
             $sessionId = $resId->GetRepositoryName();
         }
         $this->EnsureAuthenticationForSite($sessionId, true, $mimeType);
         $siteConn = new MgSiteConnection();
         $siteConn->Open($this->userInfo);
         $site = $siteConn->GetSite();
         $this->VerifyWhitelist($resId->ToString(), $mimeType, "SELECTAGGREGATES", $fmt, $site, $this->userName);
         $resSvc = $siteConn->CreateService(MgServiceType::ResourceService);
         $featSvc = $siteConn->CreateService(MgServiceType::FeatureService);
         $query = new MgFeatureAggregateOptions();
         $capsXml = MgUtils::GetProviderCapabilties($featSvc, $resSvc, $resId);
         $supportsDistinct = !(strstr($capsXml, "<SupportsSelectDistinct>true</SupportsSelectDistinct>") === false);
         $supportsCount = !(strstr($capsXml, "<Name>Count</Name>") === false);
         $supportsSpatialExtents = !(strstr($capsXml, "<Name>SpatialExtents</Name>") === false);
         switch ($type) {
             case "count":
                 $count = MgUtils::GetFeatureCount($featSvc, $resId, $schemaName, $className, $supportsCount);
                 $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?><AggregateResult>";
                 $output .= "<Type>count</Type>";
                 $output .= "<Total>{$count}</Total>";
                 $output .= "</AggregateResult>";
                 $bs = new MgByteSource($output, strlen($output));
                 $bs->SetMimeType(MgMimeType::Xml);
                 $br = $bs->GetReader();
                 if ($fmt === "json") {
                     $this->OutputXmlByteReaderAsJson($br);
                 } else {
                     $this->OutputByteReader($br);
                 }
                 break;
             case "bbox":
                 $geomName = $this->app->request->get("property");
                 $txTo = $this->app->request->get("transformto");
                 $bounds = MgUtils::GetFeatureClassMBR($this->app, $featSvc, $resId, $schemaName, $className, $geomName, $txTo);
                 $iterator = $bounds->extentGeometry->GetCoordinates();
                 $csCode = $bounds->csCode;
                 $csWkt = $bounds->coordinateSystem;
                 $epsg = $bounds->epsg;
                 $firstTime = true;
                 $minX = null;
                 $minY = null;
                 $maxX = null;
                 $maxY = null;
                 while ($iterator->MoveNext()) {
                     $x = $iterator->GetCurrent()->GetX();
                     $y = $iterator->GetCurrent()->GetY();
                     if ($firstTime) {
                         $maxX = $x;
                         $minX = $x;
                         $maxY = $y;
                         $minY = $y;
                         $firstTime = false;
                     }
                     if ($maxX < $x) {
                         $maxX = $x;
                     }
                     if ($minX > $x || $minX == 0) {
                         $minX = $x;
                     }
                     if ($maxY < $y) {
                         $maxY = $y;
                     }
                     if ($minY > $y || $minY == 0) {
                         $minY = $y;
                     }
                 }
                 $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?><AggregateResult>";
                 $output .= "<Type>bbox</Type>";
                 $output .= "<BoundingBox>";
                 $output .= "<CoordinateSystem>";
                 $output .= "<Code>{$csCode}</Code><EPSG>{$epsg}</EPSG>";
                 $output .= "</CoordinateSystem>";
                 $output .= "<LowerLeft><X>{$minX}</X><Y>{$minY}</Y></LowerLeft>";
                 $output .= "<UpperRight><X>{$maxX}</X><Y>{$maxY}</Y></UpperRight>";
                 $output .= "</BoundingBox>";
                 $output .= "</AggregateResult>";
                 $bs = new MgByteSource($output, strlen($output));
                 $bs->SetMimeType(MgMimeType::Xml);
                 $br = $bs->GetReader();
                 if ($fmt === "json") {
                     $this->OutputXmlByteReaderAsJson($br);
                 } else {
                     $this->OutputByteReader($br);
                 }
                 break;
             case "distinctvalues":
                 $values = MgUtils::GetDistinctValues($featSvc, $resId, $schemaName, $className, $distinctPropName);
                 $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?><AggregateResult>";
                 $output .= "<Type>distinctvalues</Type>";
                 $output .= "<ValueList>";
                 foreach ($values as $val) {
                     $output .= "<Value>" . MgUtils::EscapeXmlChars($val) . "</Value>";
                 }
                 $output .= "</ValueList>";
                 $output .= "</AggregateResult>";
                 $bs = new MgByteSource($output, strlen($output));
                 $bs->SetMimeType(MgMimeType::Xml);
                 $br = $bs->GetReader();
                 if ($fmt === "json") {
                     $this->OutputXmlByteReaderAsJson($br);
                 } else {
                     $this->OutputByteReader($br);
                 }
                 break;
         }
     } catch (MgException $ex) {
         $this->OnException($ex, $mimeType);
     }
 }
コード例 #4
0
 public static function CreateLayerItem($reqFeatures, $iconsPerScaleRange, $iconFormat, $iconWidth, $iconHeight, $layer, $parent, $xmldoc, $mappingService)
 {
     $xml = "<Layer>\n";
     $xml .= "<Name>" . $layer->GetName() . "</Name>\n";
     $xml .= "<Type>" . $layer->GetLayerType() . "</Type>\n";
     $xml .= "<LegendLabel>" . MgUtils::EscapeXmlChars($layer->GetLegendLabel()) . "</LegendLabel>\n";
     $xml .= "<ObjectId>" . $layer->GetObjectId() . "</ObjectId>\n";
     if ($parent != null) {
         $xml .= "<ParentId>" . $parent->GetObjectId() . "</ParentId>\n";
     }
     $xml .= "<Selectable>" . ($layer->GetSelectable() ? "true" : "false") . "</Selectable>";
     $xml .= "<DisplayInLegend>" . ($layer->GetDisplayInLegend() ? "true" : "false") . "</DisplayInLegend>\n";
     $xml .= "<ExpandInLegend>" . ($layer->GetExpandInLegend() ? "true" : "false") . "</ExpandInLegend>\n";
     $xml .= "<Visible>" . ($layer->GetVisible() ? "true" : "false") . "</Visible>\n";
     $xml .= "<ActuallyVisible>" . ($layer->IsVisible() ? "true" : "false") . "</ActuallyVisible>\n";
     $ldfId = $layer->GetLayerDefinition();
     $xml .= "<LayerDefinition>" . $ldfId->ToString() . "</LayerDefinition>\n";
     // ----------------------- Optional things if requested ------------------------- //
     if (($reqFeatures & self::REQUEST_LAYER_FEATURE_SOURCE) == self::REQUEST_LAYER_FEATURE_SOURCE) {
         $xml .= "<FeatureSource>\n";
         $xml .= "<ResourceId>" . $layer->GetFeatureSourceId() . "</ResourceId>\n";
         $xml .= "<ClassName>" . $layer->GetFeatureClassName() . "</ClassName>\n";
         $xml .= "<Geometry>" . $layer->GetFeatureGeometryName() . "</Geometry>\n";
         $xml .= "</FeatureSource>\n";
     }
     //Following code ripped from Fusion's LoadMap.php and LoadScaleRanges.php
     if ($xmldoc != null) {
         $type = 0;
         $scaleRanges = $xmldoc->getElementsByTagName('VectorScaleRange');
         if ($scaleRanges->length == 0) {
             $scaleRanges = $xmldoc->getElementsByTagName('GridScaleRange');
             if ($scaleRanges->length == 0) {
                 $scaleRanges = $xmldoc->getElementsByTagName('DrawingLayerDefinition');
                 if ($scaleRanges->length == 1) {
                     $type = 2;
                 }
             } else {
                 $type = 1;
             }
         }
         $typeStyles = array("PointTypeStyle", "LineTypeStyle", "AreaTypeStyle", "CompositeTypeStyle");
         $ruleNames = array("PointRule", "LineRule", "AreaRule", "CompositeRule");
         for ($sc = 0; $sc < $scaleRanges->length; $sc++) {
             $scaleRange = $scaleRanges->item($sc);
             $minElt = $scaleRange->getElementsByTagName('MinScale');
             $maxElt = $scaleRange->getElementsByTagName('MaxScale');
             $minScale = "0";
             $maxScale = 'infinity';
             // as MDF's VectorScaleRange::MAX_MAP_SCALE
             if ($minElt->length > 0) {
                 $minScale = $minElt->item(0)->nodeValue;
             }
             if ($maxElt->length > 0) {
                 $maxScale = $maxElt->item(0)->nodeValue;
             }
             if ($type != 0) {
                 break;
             }
             $scaleVal = 42;
             if (strcmp($maxScale, "infinity") == 0) {
                 $scaleVal = intval($minScale);
             } else {
                 $scaleVal = (intval($minScale) + intval($maxScale)) / 2.0;
             }
             $minScale = intval($minScale);
             if (strcmp($maxScale, "infinity") == 0) {
                 $maxScale = 1000000000000;
             } else {
                 $maxScale = intval($maxScale);
             }
             $xml .= "<ScaleRange>\n<MinScale>{$minScale}</MinScale>\n<MaxScale>{$maxScale}</MaxScale>\n";
             // 2 passes: First to compile icon count (to determine compression), second to write the actual XML
             $iconCount = 0;
             for ($ts = 0, $count = count($typeStyles); $ts < $count; $ts++) {
                 $typeStyle = $scaleRange->getElementsByTagName($typeStyles[$ts]);
                 for ($st = 0; $st < $typeStyle->length; $st++) {
                     // We will check if this typestyle is going to be shown in the legend
                     $showInLegend = $typeStyle->item($st)->getElementsByTagName("ShowInLegend");
                     if ($showInLegend->length > 0) {
                         if ($showInLegend->item(0)->nodeValue == "false") {
                             continue;
                         }
                     }
                     // This typestyle does not need to be shown in the legend
                     $rules = $typeStyle->item($st)->getElementsByTagName($ruleNames[$ts]);
                     $iconCount += $rules->length;
                 }
             }
             $bCompress = $iconCount > $iconsPerScaleRange;
             for ($ts = 0, $count = count($typeStyles); $ts < $count; $ts++) {
                 $typeStyle = $scaleRange->getElementsByTagName($typeStyles[$ts]);
                 $catIndex = 0;
                 if ($typeStyle->length == 0) {
                     continue;
                 }
                 $xml .= "<FeatureStyle>\n";
                 $xml .= "<Type>" . ($ts + 1) . "</Type>\n";
                 for ($st = 0; $st < $typeStyle->length; $st++) {
                     // We will check if this typestyle is going to be shown in the legend
                     $showInLegend = $typeStyle->item($st)->getElementsByTagName("ShowInLegend");
                     if ($showInLegend->length > 0) {
                         if ($showInLegend->item(0)->nodeValue == "false") {
                             continue;
                         }
                     }
                     // This typestyle does not need to be shown in the legend
                     $rules = $typeStyle->item($st)->getElementsByTagName($ruleNames[$ts]);
                     for ($r = 0; $r < $rules->length; $r++) {
                         $bRequestIcon = false;
                         if (!$bCompress) {
                             $bRequestIcon = true;
                         } else {
                             //This is a compressed theme
                             $bRequestIcon = $r == 0 || $r == $rules->length - 1;
                             //Only first and last rule
                         }
                         $rule = $rules->item($r);
                         $label = $rule->getElementsByTagName("LegendLabel");
                         $filter = $rule->getElementsByTagName("Filter");
                         $labelText = MgUtils::EscapeXmlChars($label->length == 1 ? $label->item(0)->nodeValue : "");
                         $filterText = MgUtils::EscapeXmlChars($filter->length == 1 ? $filter->item(0)->nodeValue : "");
                         $geomType = $ts + 1;
                         $themeCategory = $catIndex++;
                         $xml .= "<Rule>\n<LegendLabel>{$labelText}</LegendLabel>\n<Filter>{$filterText}</Filter>\n";
                         if ($bRequestIcon) {
                             $xml .= "<Icon>\n";
                             $xml .= MgUtils::GetLegendImageInline($mappingService, $ldfId, $scaleVal, $geomType, $themeCategory, $iconWidth, $iconHeight, $iconFormat);
                             $xml .= "</Icon>\n";
                         }
                         $xml .= "</Rule>";
                     }
                 }
                 $xml .= "</FeatureStyle>";
             }
             $xml .= "</ScaleRange>";
         }
     } else {
         $xml .= "<ScaleRange />";
     }
     $xml .= "</Layer>";
     return $xml;
 }
コード例 #5
0
 public function EscapeForXml($str)
 {
     return MgUtils::EscapeXmlChars($str);
 }
コード例 #6
0
 /**
  * Writes the GET response body based on the current record of the given MgReader. The caller must not advance to the next record
  * in the reader while inside this method
  */
 protected function GetResponseBodyRecord($reader)
 {
     $output = "<Feature>";
     $propCount = $reader->GetPropertyCount();
     for ($i = 0; $i < $propCount; $i++) {
         $name = $reader->GetPropertyName($i);
         $propType = $reader->GetPropertyType($i);
         $output .= "<Property><Name>{$name}</Name>";
         if (!$reader->IsNull($i)) {
             $output .= "<Value>";
             switch ($propType) {
                 case MgPropertyType::Boolean:
                     $output .= $reader->GetBoolean($i);
                     break;
                 case MgPropertyType::Byte:
                     $output .= $reader->GetByte($i);
                     break;
                 case MgPropertyType::DateTime:
                     $dt = $reader->GetDateTime($i);
                     $output .= $dt->ToString();
                     break;
                 case MgPropertyType::Decimal:
                 case MgPropertyType::Double:
                     $output .= $reader->GetDouble($i);
                     break;
                 case MgPropertyType::Geometry:
                     try {
                         $agf = $reader->GetGeometry($i);
                         $geom = $this->transform != null ? $this->agfRw->Read($agf, $this->transform) : $this->agfRw->Read($agf);
                         $output .= $this->wktRw->Write($geom);
                     } catch (MgException $ex) {
                     }
                     break;
                 case MgPropertyType::Int16:
                     $output .= $reader->GetInt16($i);
                     break;
                 case MgPropertyType::Int32:
                     $output .= $reader->GetInt32($i);
                     break;
                 case MgPropertyType::Int64:
                     $output .= $reader->GetInt64($i);
                     break;
                 case MgPropertyType::Single:
                     $output .= $reader->GetSingle($i);
                     break;
                 case MgPropertyType::String:
                     $output .= MgUtils::EscapeXmlChars($reader->GetString($i));
                     break;
             }
             $output .= "</Value>";
         }
         $output .= "</Property>";
     }
     $output .= "</Feature>";
     $this->app->response->write($output);
 }
コード例 #7
0
 protected function OutputMgStringCollection($strCol, $mimeType = MgMimeType::Xml)
 {
     $content = "<?xml version=\"1.0\" encoding=\"utf-8\"?><StringCollection />";
     if ($strCol != null) {
         // MgStringCollection::ToXml() doesn't seem to be reliable in PHP (bug?), so do this manually
         $count = $strCol->GetCount();
         $content = "<?xml version=\"1.0\" encoding=\"utf-8\"?><StringCollection>";
         for ($i = 0; $i < $count; $i++) {
             $value = MgUtils::EscapeXmlChars($strCol->GetItem($i));
             $content .= "<Item>{$value}</Item>";
         }
         $content .= "</StringCollection>";
     }
     if ($mimeType === MgMimeType::Json) {
         $content = MgUtils::Xml2Json($content);
     }
     $this->app->response->header("Content-Type", $mimeType);
     $this->app->response->setBody($content);
 }
コード例 #8
0
 private function OutputXml($schemas)
 {
     $read = 0;
     $agfRw = new MgAgfReaderWriter();
     $wktRw = new MgWktReaderWriter();
     $this->writer->SetHeader("Content-Type", MgMimeType::Xml);
     $this->writer->StartChunking();
     $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?><FeatureSet>";
     if (!$this->IsEmpty($schemas)) {
         $classXml = $this->featSvc->SchemaToXml($schemas);
         $classXml = substr($classXml, strpos($classXml, "<xs:schema"));
         $output .= $classXml;
     }
     $hasMoreFeatures = $this->reader->ReadNext();
     $writeXmlFooter = false;
     if ($hasMoreFeatures) {
         $output .= "<Features>";
         $this->writer->WriteChunk($output);
         $output = "";
         $writeXmlFooter = true;
     }
     $propCount = $this->reader->GetPropertyCount();
     while ($hasMoreFeatures) {
         $read++;
         if ($this->limit > 0 && $read > $this->limit) {
             break;
         }
         $output = "<Feature>";
         for ($i = 0; $i < $propCount; $i++) {
             $name = $this->reader->GetPropertyName($i);
             $propType = $this->reader->GetPropertyType($i);
             $output .= "<Property><Name>{$name}</Name>";
             if (!$this->reader->IsNull($i)) {
                 $output .= "<Value>";
                 switch ($propType) {
                     case MgPropertyType::Boolean:
                         //NOTE: It appears PHP booleans are not string-able
                         $output .= $this->reader->GetBoolean($i) ? "true" : "false";
                         break;
                     case MgPropertyType::Byte:
                         $output .= $this->reader->GetByte($i);
                         break;
                     case MgPropertyType::DateTime:
                         $dt = $this->reader->GetDateTime($i);
                         $output .= $dt->ToString();
                         break;
                     case MgPropertyType::Decimal:
                     case MgPropertyType::Double:
                         $output .= $this->reader->GetDouble($i);
                         break;
                     case MgPropertyType::Geometry:
                         try {
                             $agf = $this->reader->GetGeometry($i);
                             $geom = $this->transform != null ? $agfRw->Read($agf, $this->transform) : $agfRw->Read($agf);
                             $output .= $wktRw->Write($geom);
                         } catch (MgException $ex) {
                         }
                         break;
                     case MgPropertyType::Int16:
                         $output .= $this->reader->GetInt16($i);
                         break;
                     case MgPropertyType::Int32:
                         $output .= $this->reader->GetInt32($i);
                         break;
                     case MgPropertyType::Int64:
                         $output .= $this->reader->GetInt64($i);
                         break;
                     case MgPropertyType::Single:
                         $output .= $this->reader->GetSingle($i);
                         break;
                     case MgPropertyType::String:
                         $output .= MgUtils::EscapeXmlChars($this->reader->GetString($i));
                         break;
                 }
                 $output .= "</Value>";
             }
             $output .= "</Property>";
         }
         $output .= "</Feature>";
         $this->writer->WriteChunk($output);
         $output = "";
         $hasMoreFeatures = $this->reader->ReadNext();
     }
     if ($writeXmlFooter) {
         $output .= "</Features>";
     }
     $output .= "</FeatureSet>";
     $this->writer->WriteChunk($output);
     $this->writer->EndChunking();
     $this->reader->Close();
 }
コード例 #9
0
 private function CollectQueryMapFeaturesResult($resSvc, $reqData, $featInfo, $selection, $bRequestAttributes, $inlineSelectionImg)
 {
     $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<FeatureInformation>\n";
     $tooltip = "";
     $hyperlink = "";
     if ($featInfo != null) {
         $tooltip = $featInfo->GetTooltip();
         $hyperlink = $featInfo->GetHyperlink();
     }
     $selXml = $selection->ToXml();
     if (strlen($selXml) > 0) {
         //Need to strip the XML prolog from this fragment
         $fsdoc = new DOMDocument();
         $fsdoc->loadXML($selXml);
         $selXml = $fsdoc->saveXML($fsdoc->documentElement);
         $xml .= $selXml;
     } else {
         $xml .= "<FeatureSet />\n";
     }
     if (($reqData & self::REQUEST_TOOLTIP) == self::REQUEST_TOOLTIP && strlen($tooltip) > 0) {
         $xml .= "<Tooltip>" . MgUtils::EscapeXmlChars($tooltip) . "</Tooltip>\n";
     } else {
         $xml .= "<Tooltip />\n";
     }
     if (($reqData & self::REQUEST_HYPERLINK) == self::REQUEST_HYPERLINK && strlen($hyperlink) > 0) {
         $xml .= "<Hyperlink>" . MgUtils::EscapeXmlChars($hyperlink) . "</Hyperlink>\n";
     } else {
         $xml .= "<Hyperlink />\n";
     }
     if (($reqData & self::REQUEST_INLINE_SELECTION) == self::REQUEST_INLINE_SELECTION && $inlineSelectionImg != null) {
         $xml .= "<InlineSelectionImage>\n";
         $xml .= "<MimeType>" . $inlineSelectionImg->GetMimeType() . "</MimeType>\n";
         $b64 = MgUtils::ByteReaderToBase64($inlineSelectionImg);
         $xml .= "<Content>{$b64}</Content>\n";
         $xml .= "</InlineSelectionImage>\n";
     }
     if ($bRequestAttributes) {
         $agfRw = new MgAgfReaderWriter();
         $layerDoc = new DOMDocument();
         $xml .= "<SelectedFeatures>";
         $selLayers = $selection->GetLayers();
         if ($selLayers != null) {
             $selLayerCount = $selLayers->GetCount();
             for ($i = 0; $i < $selLayerCount; $i++) {
                 $selLayer = $selLayers->GetItem($i);
                 $layerName = $selLayer->GetName();
                 $xml .= "<SelectedLayer id=\"" . $selLayer->GetObjectId() . "\" name=\"{$layerName}\">";
                 $xml .= "<LayerMetadata>\n";
                 $ldfId = $selLayer->GetLayerDefinition();
                 $layerContent = $resSvc->GetResourceContent($ldfId);
                 $layerDoc->loadXML($layerContent->ToString());
                 $propMapNodes = $layerDoc->getElementsByTagName("PropertyMapping");
                 $clsDef = $selLayer->GetClassDefinition();
                 $clsProps = $clsDef->GetProperties();
                 $propMappings = array();
                 for ($j = 0; $j < $propMapNodes->length; $j++) {
                     $propMapNode = $propMapNodes->item($j);
                     $propName = $propMapNode->getElementsByTagName("Name")->item(0)->nodeValue;
                     $pidx = $clsProps->IndexOf($propName);
                     if ($pidx >= 0) {
                         $propDispName = MgUtils::EscapeXmlChars($propMapNode->getElementsByTagName("Value")->item(0)->nodeValue);
                         $propDef = $clsProps->GetItem($pidx);
                         $propType = MgPropertyType::Null;
                         if ($propDef->GetPropertyType() == MgFeaturePropertyType::DataProperty) {
                             $propType = $propDef->GetDataType();
                         } else {
                             if ($propDef->GetPropertyType() == MgFeaturePropertyType::DataProperty) {
                                 $propType = MgPropertyType::Geometry;
                             }
                         }
                         $xml .= "<Property>\n";
                         $xml .= "<Name>{$propName}</Name>\n<Type>{$propType}</Type>\n<DisplayName>{$propDispName}</DisplayName>\n";
                         $xml .= "</Property>\n";
                         $propMappings[$propName] = $propDispName;
                     }
                 }
                 $xml .= "</LayerMetadata>\n";
                 $reader = $selection->GetSelectedFeatures($selLayer, $selLayer->GetFeatureClassName(), false);
                 $rdrClass = $reader->GetClassDefinition();
                 $geomPropName = $rdrClass->GetDefaultGeometryPropertyName();
                 while ($reader->ReadNext()) {
                     $xml .= "<Feature>\n";
                     $bounds = "";
                     if (!$reader->IsNull($geomPropName)) {
                         $agf = $reader->GetGeometry($geomPropName);
                         $geom = $agfRw->Read($agf);
                         $env = $geom->Envelope();
                         $ll = $env->GetLowerLeftCoordinate();
                         $ur = $env->GetUpperRightCoordinate();
                         $bounds = $ll->GetX() . " " . $ll->GetY() . " " . $ur->GetX() . " " . $ur->GetY();
                     }
                     $xml .= "<Bounds>{$bounds}</Bounds>\n";
                     foreach ($propMappings as $propName => $displayName) {
                         $value = MgUtils::EscapeXmlChars(MgUtils::GetBasicValueFromReader($reader, $propName));
                         $xml .= "<Property>\n";
                         $xml .= "<Name>{$displayName}</Name>\n";
                         if (!$reader->IsNull($propName)) {
                             $xml .= "<Value>{$value}</Value>\n";
                         }
                         $xml .= "</Property>\n";
                     }
                     $xml .= "</Feature>\n";
                 }
                 $reader->Close();
                 $xml .= "</SelectedLayer>";
             }
         }
         $xml .= "</SelectedFeatures>";
     }
     $xml .= "</FeatureInformation>";
     return $xml;
 }