1 /****************************************************************************** 2 * 3 * Project: OpenGIS Simple Features Reference Implementation 4 * Purpose: OGRSpatialReference interface to OGC XML (014r4). 5 * Author: Frank Warmerdam, warmerdam@pobox.com 6 * 7 ****************************************************************************** 8 * Copyright (c) 2001, Frank Warmerdam (warmerdam@pobox.com) 9 * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com> 10 * 11 * Permission is hereby granted, free of charge, to any person obtaining a 12 * copy of this software and associated documentation files (the "Software"), 13 * to deal in the Software without restriction, including without limitation 14 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15 * and/or sell copies of the Software, and to permit persons to whom the 16 * Software is furnished to do so, subject to the following conditions: 17 * 18 * The above copyright notice and this permission notice shall be included 19 * in all copies or substantial portions of the Software. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 * DEALINGS IN THE SOFTWARE. 28 ****************************************************************************/ 29 30 #include "cpl_port.h" 31 #include "ogr_srs_api.h" 32 33 #include <cstdio> 34 #include <cstdlib> 35 #include <cstring> 36 37 #include "cpl_conv.h" 38 #include "cpl_error.h" 39 #include "cpl_minixml.h" 40 #include "cpl_multiproc.h" 41 #include "cpl_string.h" 42 #include "ogr_core.h" 43 #include "ogr_p.h" 44 #include "ogr_spatialref.h" 45 46 CPL_CVSID("$Id: ogr_srs_xml.cpp fa752ad6eabafaf630a704e1892a9d837d683cb3 2021-03-06 17:04:38 +0100 Even Rouault $") 47 48 /************************************************************************/ 49 /* parseURN() */ 50 /* */ 51 /* Parses requested sections out of URN. The passed in URN */ 52 /* *is* altered but the returned values point into the */ 53 /* original string. */ 54 /************************************************************************/ 55 56 static bool parseURN( char *pszURN, 57 const char **ppszObjectType, 58 const char **ppszAuthority, 59 const char **ppszCode, 60 const char **ppszVersion = nullptr ) 61 62 { 63 if( ppszObjectType != nullptr ) 64 *ppszObjectType = ""; 65 if( ppszAuthority != nullptr ) 66 *ppszAuthority = ""; 67 if( ppszCode != nullptr ) 68 *ppszCode = ""; 69 if( ppszVersion != nullptr ) 70 *ppszVersion = ""; 71 72 /* -------------------------------------------------------------------- */ 73 /* Verify prefix. */ 74 /* -------------------------------------------------------------------- */ 75 if( !STARTS_WITH_CI(pszURN, "urn:ogc:def:") ) 76 return false; 77 78 /* -------------------------------------------------------------------- */ 79 /* Extract object type */ 80 /* -------------------------------------------------------------------- */ 81 if( ppszObjectType != nullptr ) 82 *ppszObjectType = pszURN + 12; 83 84 int i = 12; 85 while( pszURN[i] != ':' && pszURN[i] != '\0' ) 86 i++; 87 88 if( pszURN[i] == '\0' ) 89 return false; 90 91 pszURN[i] = '\0'; 92 i++; 93 94 /* -------------------------------------------------------------------- */ 95 /* Extract authority */ 96 /* -------------------------------------------------------------------- */ 97 if( ppszAuthority != nullptr ) 98 *ppszAuthority = pszURN + i; 99 100 while( pszURN[i] != ':' && pszURN[i] != '\0' ) 101 i++; 102 103 if( pszURN[i] == '\0' ) 104 return false; 105 106 pszURN[i] = '\0'; 107 i++; 108 109 /* -------------------------------------------------------------------- */ 110 /* Extract version */ 111 /* -------------------------------------------------------------------- */ 112 if( ppszVersion != nullptr ) 113 *ppszVersion = pszURN + i; 114 115 while( pszURN[i] != ':' && pszURN[i] != '\0' ) 116 i++; 117 118 if( pszURN[i] == '\0' ) 119 return false; 120 121 pszURN[i] = '\0'; 122 i++; 123 124 /* -------------------------------------------------------------------- */ 125 /* Extract code. */ 126 /* -------------------------------------------------------------------- */ 127 if( ppszCode != nullptr ) 128 *ppszCode = pszURN + i; 129 130 return true; 131 } 132 133 /************************************************************************/ 134 /* addURN() */ 135 /************************************************************************/ 136 137 static void addURN( CPLXMLNode *psTarget, 138 const char *pszAuthority, 139 const char *pszObjectType, 140 int nCode, 141 const char *pszVersion = "" ) 142 143 { 144 if( pszVersion == nullptr ) 145 pszVersion = ""; 146 147 char szURN[200] = {}; 148 CPLAssert( strlen(pszAuthority) + strlen(pszObjectType) < 149 sizeof(szURN) - 30 ); 150 151 snprintf( szURN, sizeof(szURN), "urn:ogc:def:%s:%s:%s:", 152 pszObjectType, pszAuthority, pszVersion ); 153 154 if( nCode != 0 ) 155 snprintf( szURN + strlen(szURN), sizeof(szURN) - strlen(szURN), 156 "%d", nCode ); 157 158 CPLCreateXMLNode( 159 CPLCreateXMLNode( psTarget, CXT_Attribute, "xlink:href" ), 160 CXT_Text, szURN ); 161 } 162 163 /************************************************************************/ 164 /* AddValueIDWithURN() */ 165 /* */ 166 /* Adds element of the form <ElementName */ 167 /* xlink:href="urn_without_id">id</ElementName>" */ 168 /************************************************************************/ 169 170 static CPLXMLNode * 171 AddValueIDWithURN( CPLXMLNode *psTarget, 172 const char *pszElement, 173 const char *pszAuthority, 174 const char *pszObjectType, 175 int nCode, 176 const char *pszVersion = "" ) 177 178 { 179 CPLXMLNode *psElement 180 = CPLCreateXMLNode( psTarget, CXT_Element, pszElement ); 181 addURN( psElement, pszAuthority, pszObjectType, nCode, pszVersion ); 182 183 return psElement; 184 } 185 186 /************************************************************************/ 187 /* addAuthorityIDBlock() */ 188 /* */ 189 /* Creates a structure like: */ 190 /* <srsId> */ 191 /* <name codeSpace="urn">code</name> */ 192 /* </srsId> */ 193 /************************************************************************/ 194 static CPLXMLNode *addAuthorityIDBlock( CPLXMLNode *psTarget, 195 const char *pszElement, 196 const char *pszAuthority, 197 const char *pszObjectType, 198 int nCode, 199 const char *pszVersion = "" ) 200 201 { 202 /* -------------------------------------------------------------------- */ 203 /* Prepare partial URN without the actual code. */ 204 /* -------------------------------------------------------------------- */ 205 if( pszVersion == nullptr ) 206 pszVersion = ""; 207 208 char szURN[200] = {}; 209 CPLAssert( strlen(pszAuthority) + strlen(pszObjectType) < 210 sizeof(szURN) - 30 ); 211 212 snprintf( szURN, sizeof(szURN), "urn:ogc:def:%s:%s:%s:", 213 pszObjectType, pszAuthority, pszVersion ); 214 215 /* -------------------------------------------------------------------- */ 216 /* Prepare the base name, eg. <srsID>. */ 217 /* -------------------------------------------------------------------- */ 218 CPLXMLNode *psElement = 219 CPLCreateXMLNode( psTarget, CXT_Element, pszElement ); 220 221 /* -------------------------------------------------------------------- */ 222 /* Prepare the name element. */ 223 /* -------------------------------------------------------------------- */ 224 CPLXMLNode * psName = 225 CPLCreateXMLNode( psElement, CXT_Element, "gml:name" ); 226 227 /* -------------------------------------------------------------------- */ 228 /* Prepare the codespace attribute. */ 229 /* -------------------------------------------------------------------- */ 230 CPLCreateXMLNode( 231 CPLCreateXMLNode( psName, CXT_Attribute, "codeSpace" ), 232 CXT_Text, szURN ); 233 234 /* -------------------------------------------------------------------- */ 235 /* Attach code value to name node. */ 236 /* -------------------------------------------------------------------- */ 237 char szCode[32] = {}; 238 snprintf( szCode, sizeof(szCode), "%d", nCode ); 239 240 CPLCreateXMLNode( psName, CXT_Text, szCode ); 241 242 return psElement; 243 } 244 245 /************************************************************************/ 246 /* addGMLId() */ 247 /************************************************************************/ 248 249 static void addGMLId( CPLXMLNode *psParent ) 250 { 251 static CPLMutex *hGMLIdMutex = nullptr; 252 CPLMutexHolderD( &hGMLIdMutex ); 253 254 static int nNextGMLId = 1; 255 char szIdText[40] = {}; 256 257 snprintf( szIdText, sizeof(szIdText), "ogrcrs%d", nNextGMLId++ ); 258 259 CPLCreateXMLNode( 260 CPLCreateXMLNode( psParent, CXT_Attribute, "gml:id" ), 261 CXT_Text, szIdText ); 262 } 263 264 /************************************************************************/ 265 /* exportAuthorityToXML() */ 266 /************************************************************************/ 267 268 static CPLXMLNode *exportAuthorityToXML( const OGR_SRSNode *poAuthParent, 269 const char *pszTagName, 270 CPLXMLNode *psXMLParent, 271 const char *pszObjectType, 272 int bUseSubName = TRUE ) 273 274 { 275 /* -------------------------------------------------------------------- */ 276 /* Get authority node from parent. */ 277 /* -------------------------------------------------------------------- */ 278 const int nAuthority = poAuthParent->FindChild("AUTHORITY"); 279 if( nAuthority == -1 ) 280 return nullptr; 281 282 const OGR_SRSNode *poAuthority = poAuthParent->GetChild(nAuthority); 283 284 /* -------------------------------------------------------------------- */ 285 /* Create identification. */ 286 /* -------------------------------------------------------------------- */ 287 if(poAuthority->GetChildCount() < 2) 288 return nullptr; 289 290 const char *pszCodeSpace = poAuthority->GetChild(0)->GetValue(); 291 const char *pszCode = poAuthority->GetChild(1)->GetValue(); 292 const char *pszEdition = nullptr; 293 294 if( bUseSubName ) 295 return addAuthorityIDBlock(psXMLParent, pszTagName, pszCodeSpace, 296 pszObjectType, atoi(pszCode), pszEdition); 297 298 return AddValueIDWithURN(psXMLParent, pszTagName, pszCodeSpace, 299 pszObjectType, atoi(pszCode), pszEdition); 300 } 301 302 /************************************************************************/ 303 /* addProjArg() */ 304 /************************************************************************/ 305 306 static void addProjArg( const OGRSpatialReference *poSRS, CPLXMLNode *psBase, 307 const char *pszMeasureType, double dfDefault, 308 int nParameterID, const char *pszWKTName ) 309 310 { 311 CPLXMLNode *psNode = CPLCreateXMLNode(psBase, CXT_Element, "gml:usesValue"); 312 313 /* -------------------------------------------------------------------- */ 314 /* Handle the UOM. */ 315 /* -------------------------------------------------------------------- */ 316 const char *pszUOMValue = EQUAL(pszMeasureType, "Angular") 317 ? "urn:ogc:def:uom:EPSG::9102" 318 : "urn:ogc:def:uom:EPSG::9001"; 319 320 CPLXMLNode *psValue = CPLCreateXMLNode(psNode, CXT_Element, "gml:value"); 321 322 CPLCreateXMLNode( 323 CPLCreateXMLNode( psValue, CXT_Attribute, "uom" ), 324 CXT_Text, pszUOMValue ); 325 326 /* -------------------------------------------------------------------- */ 327 /* Add the parameter value itself. */ 328 /* -------------------------------------------------------------------- */ 329 double dfParamValue = poSRS->GetNormProjParm( pszWKTName, dfDefault, nullptr ); 330 331 CPLCreateXMLNode( psValue, CXT_Text, 332 CPLString().Printf( "%.16g", dfParamValue ) ); 333 334 /* -------------------------------------------------------------------- */ 335 /* Add the valueOfParameter. */ 336 /* -------------------------------------------------------------------- */ 337 AddValueIDWithURN( psNode, "gml:valueOfParameter", "EPSG", "parameter", 338 nParameterID ); 339 } 340 341 /************************************************************************/ 342 /* addAxis() */ 343 /* */ 344 /* Added the <usesAxis> element and down. */ 345 /************************************************************************/ 346 347 static CPLXMLNode *addAxis( CPLXMLNode *psXMLParent, 348 const char *pszAxis, // "Lat", "Long", "E" or "N" 349 const OGR_SRSNode * /* poUnitsSrc */ ) 350 351 { 352 CPLXMLNode *psAxisXML = 353 CPLCreateXMLNode( 354 CPLCreateXMLNode( psXMLParent, CXT_Element, "gml:usesAxis" ), 355 CXT_Element, "gml:CoordinateSystemAxis" ); 356 if( !psAxisXML ) 357 { 358 CPLError( CE_Failure, CPLE_AppDefined, "addAxis failed." ); 359 return nullptr; 360 } 361 addGMLId( psAxisXML ); 362 363 if( EQUAL(pszAxis, "Lat") ) 364 { 365 CPLCreateXMLNode( 366 CPLCreateXMLNode( psAxisXML, CXT_Attribute, "gml:uom" ), 367 CXT_Text, "urn:ogc:def:uom:EPSG::9102" ); 368 369 CPLCreateXMLElementAndValue( psAxisXML, "gml:name", 370 "Geodetic latitude" ); 371 addAuthorityIDBlock( psAxisXML, "gml:axisID", "EPSG", "axis", 9901 ); 372 CPLCreateXMLElementAndValue( psAxisXML, "gml:axisAbbrev", "Lat" ); 373 CPLCreateXMLElementAndValue( psAxisXML, "gml:axisDirection", "north" ); 374 } 375 else if( EQUAL(pszAxis, "Long") ) 376 { 377 CPLCreateXMLNode( 378 CPLCreateXMLNode( psAxisXML, CXT_Attribute, "gml:uom" ), 379 CXT_Text, "urn:ogc:def:uom:EPSG::9102" ); 380 381 CPLCreateXMLElementAndValue( psAxisXML, "gml:name", 382 "Geodetic longitude" ); 383 addAuthorityIDBlock( psAxisXML, "gml:axisID", "EPSG", "axis", 9902 ); 384 CPLCreateXMLElementAndValue( psAxisXML, "gml:axisAbbrev", "Lon" ); 385 CPLCreateXMLElementAndValue( psAxisXML, "gml:axisDirection", "east" ); 386 } 387 else if( EQUAL(pszAxis, "E") ) 388 { 389 CPLCreateXMLNode( 390 CPLCreateXMLNode( psAxisXML, CXT_Attribute, "gml:uom" ), 391 CXT_Text, "urn:ogc:def:uom:EPSG::9001" ); 392 393 CPLCreateXMLElementAndValue( psAxisXML, "gml:name", "Easting" ); 394 addAuthorityIDBlock( psAxisXML, "gml:axisID", "EPSG", "axis", 9906 ); 395 CPLCreateXMLElementAndValue( psAxisXML, "gml:axisAbbrev", "E" ); 396 CPLCreateXMLElementAndValue( psAxisXML, "gml:axisDirection", "east" ); 397 } 398 else if( EQUAL(pszAxis, "N") ) 399 { 400 CPLCreateXMLNode( 401 CPLCreateXMLNode( psAxisXML, CXT_Attribute, "gml:uom" ), 402 CXT_Text, "urn:ogc:def:uom:EPSG::9001" ); 403 404 CPLCreateXMLElementAndValue( psAxisXML, "gml:name", "Northing" ); 405 addAuthorityIDBlock( psAxisXML, "gml:axisID", "EPSG", "axis", 9907 ); 406 CPLCreateXMLElementAndValue( psAxisXML, "gml:axisAbbrev", "N" ); 407 CPLCreateXMLElementAndValue( psAxisXML, "gml:axisDirection", "north" ); 408 } 409 else 410 { 411 CPLAssert( false ); 412 } 413 414 return psAxisXML; 415 } 416 417 /************************************************************************/ 418 /* exportGeogCSToXML() */ 419 /************************************************************************/ 420 421 static CPLXMLNode *exportGeogCSToXML( const OGRSpatialReference *poSRS ) 422 423 { 424 const OGR_SRSNode *poGeogCS = poSRS->GetAttrNode( "GEOGCS" ); 425 426 if( poGeogCS == nullptr ) 427 return nullptr; 428 429 /* -------------------------------------------------------------------- */ 430 /* Establish initial infrastructure. */ 431 /* -------------------------------------------------------------------- */ 432 CPLXMLNode *psGCS_XML = 433 CPLCreateXMLNode( nullptr, CXT_Element, "gml:GeographicCRS" ); 434 addGMLId( psGCS_XML ); 435 436 /* -------------------------------------------------------------------- */ 437 /* Attach symbolic name (srsName). */ 438 /* -------------------------------------------------------------------- */ 439 CPLCreateXMLElementAndValue( psGCS_XML, "gml:srsName", 440 poGeogCS->GetChild(0)->GetValue() ); 441 442 /* -------------------------------------------------------------------- */ 443 /* Does the overall coordinate system have an authority? If so */ 444 /* attach as an identification section. */ 445 /* -------------------------------------------------------------------- */ 446 exportAuthorityToXML( poGeogCS, "gml:srsID", psGCS_XML, "crs" ); 447 448 /* -------------------------------------------------------------------- */ 449 /* Insert a big whack of fixed stuff defining the */ 450 /* ellipsoidalCS. Basically this defines the axes and their */ 451 /* units. */ 452 /* -------------------------------------------------------------------- */ 453 CPLXMLNode *psECS = 454 CPLCreateXMLNode( 455 CPLCreateXMLNode( psGCS_XML, CXT_Element, "gml:usesEllipsoidalCS" ), 456 CXT_Element, "gml:EllipsoidalCS" ); 457 458 addGMLId( psECS ); 459 460 CPLCreateXMLElementAndValue( psECS, "gml:csName", "ellipsoidal" ); 461 462 addAuthorityIDBlock( psECS, "gml:csID", "EPSG", "cs", 6402 ); 463 464 addAxis( psECS, "Lat", nullptr ); 465 addAxis( psECS, "Long", nullptr ); 466 467 /* -------------------------------------------------------------------- */ 468 /* Start with the datum. */ 469 /* -------------------------------------------------------------------- */ 470 const OGR_SRSNode *poDatum = poGeogCS->GetNode( "DATUM" ); 471 472 if( poDatum == nullptr ) 473 { 474 CPLDestroyXMLNode( psGCS_XML ); 475 return nullptr; 476 } 477 478 CPLXMLNode *psDatumXML = 479 CPLCreateXMLNode( 480 CPLCreateXMLNode( psGCS_XML, CXT_Element, "gml:usesGeodeticDatum" ), 481 CXT_Element, "gml:GeodeticDatum" ); 482 483 addGMLId( psDatumXML ); 484 485 /* -------------------------------------------------------------------- */ 486 /* Set the datumName. */ 487 /* -------------------------------------------------------------------- */ 488 CPLCreateXMLElementAndValue( psDatumXML, "gml:datumName", 489 poDatum->GetChild(0)->GetValue() ); 490 491 /* -------------------------------------------------------------------- */ 492 /* Set authority id info if available. */ 493 /* -------------------------------------------------------------------- */ 494 exportAuthorityToXML( poDatum, "gml:datumID", psDatumXML, "datum" ); 495 496 /* -------------------------------------------------------------------- */ 497 /* Setup prime meridian information. */ 498 /* -------------------------------------------------------------------- */ 499 const OGR_SRSNode *poPMNode = poGeogCS->GetNode( "PRIMEM" ); 500 const char *pszPMName = "Greenwich"; 501 double dfPMOffset = poSRS->GetPrimeMeridian( &pszPMName ); 502 503 CPLXMLNode *psPM = 504 CPLCreateXMLNode( 505 CPLCreateXMLNode(psDatumXML, CXT_Element, "gml:usesPrimeMeridian"), 506 CXT_Element, "gml:PrimeMeridian"); 507 508 addGMLId( psPM ); 509 510 CPLCreateXMLElementAndValue( psPM, "gml:meridianName", pszPMName ); 511 512 if( poPMNode ) 513 exportAuthorityToXML( poPMNode, "gml:meridianID", psPM, "meridian" ); 514 515 CPLXMLNode *psAngle = 516 CPLCreateXMLNode( 517 CPLCreateXMLNode( psPM, CXT_Element, "gml:greenwichLongitude" ), 518 CXT_Element, "gml:angle" ); 519 520 CPLCreateXMLNode( CPLCreateXMLNode( psAngle, CXT_Attribute, "uom" ), 521 CXT_Text, "urn:ogc:def:uom:EPSG::9102" ); 522 523 CPLCreateXMLNode( psAngle, CXT_Text, 524 CPLString().Printf( "%.16g", dfPMOffset ) ); 525 526 /* -------------------------------------------------------------------- */ 527 /* Translate the ellipsoid. */ 528 /* -------------------------------------------------------------------- */ 529 const OGR_SRSNode *poEllipsoid = poDatum->GetNode( "SPHEROID" ); 530 531 if( poEllipsoid != nullptr ) 532 { 533 CPLXMLNode *psEllipseXML = 534 CPLCreateXMLNode( 535 CPLCreateXMLNode(psDatumXML, CXT_Element, "gml:usesEllipsoid" ), 536 CXT_Element, "gml:Ellipsoid" ); 537 538 addGMLId( psEllipseXML ); 539 540 CPLCreateXMLElementAndValue( psEllipseXML, "gml:ellipsoidName", 541 poEllipsoid->GetChild(0)->GetValue() ); 542 543 exportAuthorityToXML( poEllipsoid, "gml:ellipsoidID", psEllipseXML, 544 "ellipsoid"); 545 546 CPLXMLNode *psParamXML = 547 CPLCreateXMLNode( psEllipseXML, CXT_Element, "gml:semiMajorAxis" ); 548 549 CPLCreateXMLNode( CPLCreateXMLNode(psParamXML, CXT_Attribute, "uom"), 550 CXT_Text, "urn:ogc:def:uom:EPSG::9001" ); 551 552 CPLCreateXMLNode( psParamXML, CXT_Text, 553 poEllipsoid->GetChild(1)->GetValue() ); 554 555 psParamXML = 556 CPLCreateXMLNode( 557 CPLCreateXMLNode( psEllipseXML, CXT_Element, 558 "gml:secondDefiningParameter" ), 559 CXT_Element, "gml:inverseFlattening" ); 560 561 CPLCreateXMLNode( CPLCreateXMLNode(psParamXML, CXT_Attribute, "uom"), 562 CXT_Text, "urn:ogc:def:uom:EPSG::9201" ); 563 564 CPLCreateXMLNode( psParamXML, CXT_Text, 565 poEllipsoid->GetChild(2)->GetValue() ); 566 } 567 568 return psGCS_XML; 569 } 570 571 /************************************************************************/ 572 /* exportProjCSToXML() */ 573 /************************************************************************/ 574 575 static CPLXMLNode *exportProjCSToXML( const OGRSpatialReference *poSRS ) 576 577 { 578 const OGR_SRSNode *poProjCS = poSRS->GetAttrNode( "PROJCS" ); 579 580 if( poProjCS == nullptr ) 581 return nullptr; 582 583 /* -------------------------------------------------------------------- */ 584 /* Establish initial infrastructure. */ 585 /* -------------------------------------------------------------------- */ 586 CPLXMLNode *psCRS_XML = 587 CPLCreateXMLNode( nullptr, CXT_Element, "gml:ProjectedCRS" ); 588 addGMLId( psCRS_XML ); 589 590 /* -------------------------------------------------------------------- */ 591 /* Attach symbolic name (a name in a nameset). */ 592 /* -------------------------------------------------------------------- */ 593 CPLCreateXMLElementAndValue( psCRS_XML, "gml:srsName", 594 poProjCS->GetChild(0)->GetValue() ); 595 596 /* -------------------------------------------------------------------- */ 597 /* Add authority info if we have it. */ 598 /* -------------------------------------------------------------------- */ 599 exportAuthorityToXML( poProjCS, "gml:srsID", psCRS_XML, "crs" ); 600 601 /* -------------------------------------------------------------------- */ 602 /* Use the GEOGCS as a <baseCRS> */ 603 /* -------------------------------------------------------------------- */ 604 CPLXMLNode *psBaseCRSXML = 605 CPLCreateXMLNode( psCRS_XML, CXT_Element, "gml:baseCRS" ); 606 607 CPLAddXMLChild( psBaseCRSXML, exportGeogCSToXML( poSRS ) ); 608 609 /* -------------------------------------------------------------------- */ 610 /* Our projected coordinate system is "defined by Conversion". */ 611 /* -------------------------------------------------------------------- */ 612 CPLXMLNode *psDefinedBy = 613 CPLCreateXMLNode( psCRS_XML, CXT_Element, "gml:definedByConversion" ); 614 615 /* -------------------------------------------------------------------- */ 616 /* Projections are handled as ParameterizedTransformations. */ 617 /* -------------------------------------------------------------------- */ 618 const char *pszProjection = poSRS->GetAttrValue("PROJECTION"); 619 CPLXMLNode *psConv = 620 CPLCreateXMLNode( psDefinedBy, CXT_Element, "gml:Conversion"); 621 addGMLId( psConv ); 622 623 CPLCreateXMLNode( 624 CPLCreateXMLNode(psConv, CXT_Element, "gml:coordinateOperationName"), 625 CXT_Text, pszProjection); 626 627 /* -------------------------------------------------------------------- */ 628 /* Transverse Mercator */ 629 /* -------------------------------------------------------------------- */ 630 if( pszProjection == nullptr ) 631 { 632 CPLError(CE_Failure, CPLE_NotSupported, "No projection method"); 633 } 634 else if( EQUAL(pszProjection, SRS_PT_TRANSVERSE_MERCATOR) ) 635 { 636 AddValueIDWithURN( psConv, "gml:usesMethod", "EPSG", "method", 9807 ); 637 638 addProjArg( poSRS, psConv, "Angular", 0.0, 639 8801, SRS_PP_LATITUDE_OF_ORIGIN ); 640 addProjArg( poSRS, psConv, "Angular", 0.0, 641 8802, SRS_PP_CENTRAL_MERIDIAN ); 642 addProjArg( poSRS, psConv, "Unitless", 1.0, 643 8805, SRS_PP_SCALE_FACTOR ); 644 addProjArg( poSRS, psConv, "Linear", 0.0, 645 8806, SRS_PP_FALSE_EASTING ); 646 addProjArg( poSRS, psConv, "Linear", 0.0, 647 8807, SRS_PP_FALSE_NORTHING ); 648 } 649 /* -------------------------------------------------------------------- */ 650 /* Lambert Conformal Conic */ 651 /* -------------------------------------------------------------------- */ 652 else if( EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP) ) 653 { 654 AddValueIDWithURN( psConv, "gml:usesMethod", "EPSG", "method", 655 9801 ); 656 657 addProjArg( poSRS, psConv, "Angular", 0.0, 658 8801, SRS_PP_LATITUDE_OF_ORIGIN ); 659 addProjArg( poSRS, psConv, "Angular", 0.0, 660 8802, SRS_PP_CENTRAL_MERIDIAN ); 661 addProjArg( poSRS, psConv, "Unitless", 1.0, 662 8805, SRS_PP_SCALE_FACTOR ); 663 addProjArg( poSRS, psConv, "Linear", 0.0, 664 8806, SRS_PP_FALSE_EASTING ); 665 addProjArg( poSRS, psConv, "Linear", 0.0, 666 8807, SRS_PP_FALSE_NORTHING ); 667 } 668 else 669 { 670 CPLError(CE_Warning, CPLE_NotSupported, 671 "Unhandled projection method %s", pszProjection); 672 } 673 674 /* -------------------------------------------------------------------- */ 675 /* Define the cartesian coordinate system. */ 676 /* -------------------------------------------------------------------- */ 677 CPLXMLNode *psCCS = 678 CPLCreateXMLNode( 679 CPLCreateXMLNode( psCRS_XML, CXT_Element, "gml:usesCartesianCS" ), 680 CXT_Element, "gml:CartesianCS" ); 681 682 addGMLId( psCCS ); 683 684 CPLCreateXMLElementAndValue( psCCS, "gml:csName", "Cartesian" ); 685 addAuthorityIDBlock( psCCS, "gml:csID", "EPSG", "cs", 4400 ); 686 addAxis( psCCS, "E", nullptr ); 687 addAxis( psCCS, "N", nullptr ); 688 689 return psCRS_XML; 690 } 691 692 /************************************************************************/ 693 /* exportToXML() */ 694 /************************************************************************/ 695 696 /** 697 * \brief Export coordinate system in XML format. 698 * 699 * Converts the loaded coordinate reference system into XML format 700 * to the extent possible. The string returned in ppszRawXML should be 701 * deallocated by the caller with CPLFree() when no longer needed. 702 * 703 * LOCAL_CS coordinate systems are not translatable. An empty string 704 * will be returned along with OGRERR_NONE. 705 * 706 * This method is the equivalent of the C function OSRExportToXML(). 707 * 708 * @param ppszRawXML pointer to which dynamically allocated XML definition 709 * will be assigned. 710 * @param pszDialect currently ignored. The dialect used is GML based. 711 * 712 * @return OGRERR_NONE on success or an error code on failure. 713 */ 714 715 OGRErr OGRSpatialReference::exportToXML( char **ppszRawXML, 716 CPL_UNUSED const char * pszDialect ) const 717 { 718 CPLXMLNode *psXMLTree = nullptr; 719 720 if( IsGeographic() ) 721 { 722 psXMLTree = exportGeogCSToXML( this ); 723 } 724 else if( IsProjected() ) 725 { 726 psXMLTree = exportProjCSToXML( this ); 727 } 728 else 729 return OGRERR_UNSUPPORTED_SRS; 730 731 *ppszRawXML = CPLSerializeXMLTree( psXMLTree ); 732 CPLDestroyXMLNode( psXMLTree ); 733 734 return OGRERR_NONE; 735 } 736 737 /************************************************************************/ 738 /* OSRExportToXML() */ 739 /************************************************************************/ 740 /** 741 * \brief Export coordinate system in XML format. 742 * 743 * This function is the same as OGRSpatialReference::exportToXML(). 744 */ 745 746 OGRErr OSRExportToXML( OGRSpatialReferenceH hSRS, char **ppszRawXML, 747 const char *pszDialect ) 748 749 { 750 VALIDATE_POINTER1( hSRS, "OSRExportToXML", OGRERR_FAILURE ); 751 752 return OGRSpatialReference::FromHandle(hSRS)->exportToXML( ppszRawXML, 753 pszDialect ); 754 } 755 756 #ifdef notdef 757 /************************************************************************/ 758 /* importXMLUnits() */ 759 /************************************************************************/ 760 761 static void importXMLUnits( CPLXMLNode *psSrcXML, const char *pszClass, 762 OGRSpatialReference *poSRS, const char *pszTarget) 763 764 { 765 OGR_SRSNode *poNode = poSRS->GetAttrNode( pszTarget ); 766 767 CPLAssert( EQUAL(pszClass, "AngularUnit") 768 || EQUAL(pszClass, "LinearUnit") ); 769 770 psSrcXML = CPLGetXMLNode( psSrcXML, pszClass ); 771 772 OGR_SRSNode *poUnits = NULL; 773 const char *pszUnitName = NULL; 774 const char *pszUnitsPer = NULL; 775 776 // TODO(schwehr): Remove the goto. 777 if( psSrcXML == NULL ) 778 goto DefaultTarget; 779 780 pszUnitName = 781 CPLGetXMLValue( psSrcXML, "NameSet.name", "unnamed" ); 782 783 pszUnitsPer = 784 EQUAL(pszClass, "AngularUnit") 785 ? CPLGetXMLValue( psSrcXML, "radiansPerUnit", NULL ) 786 : CPLGetXMLValue( psSrcXML, "metresPerUnit", NULL ); 787 788 if( pszUnitsPer == NULL ) 789 { 790 CPLDebug( "OGR_SRS_XML", "Missing PerUnit value for %s.", pszClass ); 791 goto DefaultTarget; 792 } 793 794 if( poNode == NULL ) 795 { 796 CPLDebug("OGR_SRS_XML", "Can't find %s in importXMLUnits.", pszTarget); 797 goto DefaultTarget; 798 } 799 800 if( poNode->FindChild("UNIT") != -1 ) 801 { 802 poUnits = poNode->GetChild( poNode->FindChild( "UNIT" ) ); 803 poUnits->GetChild(0)->SetValue( pszUnitName ); 804 poUnits->GetChild(1)->SetValue( pszUnitsPer ); 805 } 806 else 807 { 808 poUnits = new OGR_SRSNode( "UNIT" ); 809 poUnits->AddChild( new OGR_SRSNode( pszUnitName ) ); 810 poUnits->AddChild( new OGR_SRSNode( pszUnitsPer ) ); 811 812 poNode->AddChild( poUnits ); 813 } 814 return; 815 816 DefaultTarget: 817 poUnits = new OGR_SRSNode( "UNIT" ); 818 if( EQUAL(pszClass, "AngularUnit") ) 819 { 820 poUnits->AddChild( new OGR_SRSNode( SRS_UA_DEGREE ) ); 821 poUnits->AddChild( new OGR_SRSNode( SRS_UA_DEGREE_CONV ) ); 822 } 823 else 824 { 825 poUnits->AddChild( new OGR_SRSNode( SRS_UL_METER ) ); 826 poUnits->AddChild( new OGR_SRSNode( "1.0" ) ); 827 } 828 829 poNode->AddChild( poUnits ); 830 } 831 #endif 832 833 /************************************************************************/ 834 /* importXMLAuthority() */ 835 /************************************************************************/ 836 837 static void importXMLAuthority( CPLXMLNode *psSrcXML, 838 OGRSpatialReference *poSRS, 839 const char *pszSourceKey, 840 const char *pszTargetKey ) 841 842 { 843 CPLXMLNode *psIDNode = CPLGetXMLNode( psSrcXML, pszSourceKey ); 844 CPLXMLNode *psNameNode = CPLGetXMLNode( psIDNode, "name" ); 845 CPLXMLNode *psCodeSpace = CPLGetXMLNode( psNameNode, "codeSpace" ); 846 847 if( psIDNode == nullptr || psNameNode == nullptr || psCodeSpace == nullptr ) 848 return; 849 850 char *pszURN = CPLStrdup(CPLGetXMLValue( psCodeSpace, "", "" )); 851 852 const char *pszAuthority; 853 const char *pszCode; 854 if( !parseURN( pszURN, nullptr, &pszAuthority, &pszCode ) ) 855 { 856 CPLFree( pszURN ); 857 return; 858 } 859 860 if( strlen(pszCode) == 0 ) 861 pszCode = CPLGetXMLValue( psNameNode, "", "" ); 862 863 const int nCode = pszCode != nullptr ? atoi(pszCode) :0; 864 865 if( nCode != 0 ) 866 poSRS->SetAuthority( pszTargetKey, pszAuthority, nCode ); 867 868 CPLFree( pszURN ); 869 } 870 871 /************************************************************************/ 872 /* ParseOGCDefURN() */ 873 /* */ 874 /* Parse out fields from a URN of the form: */ 875 /* urn:ogc:def:parameter:EPSG:6.3:9707 */ 876 /************************************************************************/ 877 878 static bool ParseOGCDefURN( const char *pszURN, 879 CPLString *poObjectType, 880 CPLString *poAuthority, 881 CPLString *poVersion, 882 CPLString *poValue ) 883 884 { 885 if( poObjectType != nullptr ) 886 *poObjectType = ""; 887 888 if( poAuthority != nullptr ) 889 *poAuthority = ""; 890 891 if( poVersion != nullptr ) 892 *poVersion = ""; 893 894 if( poValue != nullptr ) 895 *poValue = ""; 896 897 if( pszURN == nullptr || !STARTS_WITH_CI(pszURN, "urn:ogc:def:") ) 898 return false; 899 900 char **papszTokens = CSLTokenizeStringComplex( pszURN + 12, ":", 901 FALSE, TRUE ); 902 903 if( CSLCount(papszTokens) != 4 ) 904 { 905 CSLDestroy( papszTokens ); 906 return false; 907 } 908 909 if( poObjectType != nullptr ) 910 *poObjectType = papszTokens[0]; 911 912 if( poAuthority != nullptr ) 913 *poAuthority = papszTokens[1]; 914 915 if( poVersion != nullptr ) 916 *poVersion = papszTokens[2]; 917 918 if( poValue != nullptr ) 919 *poValue = papszTokens[3]; 920 921 CSLDestroy( papszTokens ); 922 return true; 923 } 924 925 /************************************************************************/ 926 /* getEPSGObjectCodeValue() */ 927 /* */ 928 /* Fetch a code value from the indicated node. Should work on */ 929 /* something of the form <elem xlink:href="urn:...:n" /> or */ 930 /* something of the form <elem xlink:href="urn:...:">n</a>. */ 931 /************************************************************************/ 932 933 static int getEPSGObjectCodeValue( CPLXMLNode *psNode, 934 const char *pszEPSGObjectType, /*"method" */ 935 int nDefault ) 936 937 { 938 if( psNode == nullptr ) 939 return nDefault; 940 941 const char* pszHrefVal = CPLGetXMLValue( psNode, "xlink:href", nullptr ); 942 if( pszHrefVal == nullptr ) 943 pszHrefVal = CPLGetXMLValue( psNode, "href", nullptr ); 944 945 CPLString osObjectType; 946 CPLString osAuthority; 947 CPLString osValue; 948 if( !ParseOGCDefURN( pszHrefVal, 949 &osObjectType, &osAuthority, nullptr, &osValue ) ) 950 return nDefault; 951 952 if( !EQUAL(osAuthority, "EPSG") 953 || !EQUAL(osObjectType, pszEPSGObjectType) ) 954 return nDefault; 955 956 if( !osValue.empty() ) 957 return atoi(osValue); 958 959 const char *pszValue = CPLGetXMLValue( psNode, "", nullptr); 960 if( pszValue != nullptr ) 961 return atoi(pszValue); 962 963 return nDefault; 964 } 965 966 /************************************************************************/ 967 /* getProjectionParam() */ 968 /************************************************************************/ 969 970 static double getProjectionParam( CPLXMLNode *psRootNode, 971 int nParameterCode, 972 const char * /*pszMeasureType */, 973 double dfDefault ) 974 975 { 976 for( CPLXMLNode *psUsesParameter = psRootNode->psChild; 977 psUsesParameter != nullptr; 978 psUsesParameter = psUsesParameter->psNext ) 979 { 980 if( psUsesParameter->eType != CXT_Element ) 981 continue; 982 983 if( !EQUAL(psUsesParameter->pszValue, "usesParameterValue") 984 && !EQUAL(psUsesParameter->pszValue, "usesValue") ) 985 continue; 986 987 if( getEPSGObjectCodeValue( CPLGetXMLNode(psUsesParameter, 988 "valueOfParameter"), 989 "parameter", 0 ) == nParameterCode ) 990 { 991 const char *pszValue = CPLGetXMLValue( psUsesParameter, "value", 992 nullptr ); 993 994 if( pszValue == nullptr ) 995 return dfDefault; 996 997 return CPLAtof(pszValue); 998 } 999 } 1000 1001 return dfDefault; 1002 } 1003 1004 /************************************************************************/ 1005 /* getNormalizedValue() */ 1006 /* */ 1007 /* Parse a node to get its numerical value, and then normalize */ 1008 /* into meters of degrees depending on the measure type. */ 1009 /************************************************************************/ 1010 1011 static double getNormalizedValue( CPLXMLNode *psNode, const char *pszPath, 1012 const char * /*pszMeasure*/, 1013 double dfDefault ) 1014 1015 { 1016 CPLXMLNode *psTargetNode = pszPath == nullptr || strlen(pszPath) == 0 1017 ? psNode 1018 : CPLGetXMLNode( psNode, pszPath ); 1019 1020 if( psTargetNode == nullptr ) 1021 return dfDefault; 1022 1023 CPLXMLNode *psValueNode = psTargetNode->psChild; // Used after for. 1024 for( ; 1025 psValueNode != nullptr && psValueNode->eType != CXT_Text; 1026 psValueNode = psValueNode->psNext ) {} 1027 1028 if( psValueNode == nullptr ) 1029 return dfDefault; 1030 1031 // Add normalization later. 1032 1033 return CPLAtof(psValueNode->pszValue); 1034 } 1035 1036 /************************************************************************/ 1037 /* importGeogCSFromXML() */ 1038 /************************************************************************/ 1039 1040 static OGRErr importGeogCSFromXML( OGRSpatialReference *poSRS, 1041 CPLXMLNode *psCRS ) 1042 1043 { 1044 /* -------------------------------------------------------------------- */ 1045 /* Set the GEOGCS name from the srsName. */ 1046 /* -------------------------------------------------------------------- */ 1047 const char *pszGeogName = 1048 CPLGetXMLValue( psCRS, "srsName", "Unnamed GeogCS" ); 1049 1050 /* -------------------------------------------------------------------- */ 1051 /* If we don't seem to have a detailed coordinate system */ 1052 /* definition, check if we can define based on an EPSG code. */ 1053 /* -------------------------------------------------------------------- */ 1054 CPLXMLNode *psDatum = 1055 CPLGetXMLNode( psCRS, "usesGeodeticDatum.GeodeticDatum" ); 1056 1057 if( psDatum == nullptr ) 1058 { 1059 OGRSpatialReference oIdSRS; 1060 1061 oIdSRS.SetLocalCS( "dummy" ); 1062 importXMLAuthority( psCRS, &oIdSRS, "srsID", "LOCAL_CS" ); 1063 1064 if( oIdSRS.GetAuthorityCode( "LOCAL_CS" ) != nullptr 1065 && oIdSRS.GetAuthorityName( "LOCAL_CS" ) != nullptr 1066 && EQUAL(oIdSRS.GetAuthorityName("LOCAL_CS"), "EPSG") ) 1067 { 1068 return poSRS->importFromEPSG( 1069 atoi(oIdSRS.GetAuthorityCode("LOCAL_CS")) ); 1070 } 1071 } 1072 1073 /* -------------------------------------------------------------------- */ 1074 /* Get datum name. */ 1075 /* -------------------------------------------------------------------- */ 1076 const char *pszDatumName = 1077 CPLGetXMLValue( psDatum, "datumName", "Unnamed Datum" ); 1078 1079 /* -------------------------------------------------------------------- */ 1080 /* Get ellipsoid information. */ 1081 /* -------------------------------------------------------------------- */ 1082 CPLXMLNode *psE = CPLGetXMLNode( psDatum, "usesEllipsoid.Ellipsoid" ); 1083 const char *pszEllipsoidName = 1084 CPLGetXMLValue( psE, "ellipsoidName", "Unnamed Ellipsoid" ); 1085 1086 const double dfSemiMajor = 1087 getNormalizedValue( psE, "semiMajorAxis", "Linear", 1088 SRS_WGS84_SEMIMAJOR ); 1089 1090 const double dfInvFlattening = 1091 getNormalizedValue( psE, "secondDefiningParameter.inverseFlattening", 1092 "Unitless", 0.0 ); 1093 1094 if( dfInvFlattening == 0.0 ) 1095 { 1096 CPLError( CE_Failure, CPLE_AppDefined, 1097 "Ellipsoid inverseFlattening corrupt or missing." ); 1098 return OGRERR_CORRUPT_DATA; 1099 } 1100 1101 /* -------------------------------------------------------------------- */ 1102 /* Get the prime meridian. */ 1103 /* -------------------------------------------------------------------- */ 1104 const char *pszPMName = nullptr; 1105 double dfPMOffset = 0.0; 1106 1107 CPLXMLNode *psPM = 1108 CPLGetXMLNode( psDatum, "usesPrimeMeridian.PrimeMeridian" ); 1109 if( psPM == nullptr ) 1110 { 1111 pszPMName = "Greenwich"; 1112 dfPMOffset = 0.0; 1113 } 1114 else 1115 { 1116 pszPMName = CPLGetXMLValue( psPM, "meridianName", 1117 "Unnamed Prime Meridian"); 1118 dfPMOffset = 1119 getNormalizedValue( psPM, "greenwichLongitude.angle", 1120 "Angular", 0.0 ); 1121 } 1122 1123 /* -------------------------------------------------------------------- */ 1124 /* Set the geographic definition. */ 1125 /* -------------------------------------------------------------------- */ 1126 poSRS->SetGeogCS( pszGeogName, pszDatumName, 1127 pszEllipsoidName, dfSemiMajor, dfInvFlattening, 1128 pszPMName, dfPMOffset ); 1129 1130 /* -------------------------------------------------------------------- */ 1131 /* Look for angular units. We don't check that all axes match */ 1132 /* at this time. */ 1133 /* -------------------------------------------------------------------- */ 1134 #if 0 // Does not compile. 1135 CPLXMLNode *psAxis = 1136 CPLGetXMLNode( psGeo2DCRS, 1137 "EllipsoidalCoordinateSystem.CoordinateAxis" ); 1138 importXMLUnits( psAxis, "AngularUnit", poSRS, "GEOGCS" ); 1139 #endif 1140 1141 /* -------------------------------------------------------------------- */ 1142 /* Can we set authorities for any of the levels? */ 1143 /* -------------------------------------------------------------------- */ 1144 importXMLAuthority( psCRS, poSRS, "srsID", "GEOGCS" ); 1145 importXMLAuthority( psDatum, poSRS, "datumID", "GEOGCS|DATUM" ); 1146 importXMLAuthority( psE, poSRS, "ellipsoidID", 1147 "GEOGCS|DATUM|SPHEROID" ); 1148 importXMLAuthority( psDatum, poSRS, 1149 "usesPrimeMeridian.PrimeMeridian.meridianID", 1150 "GEOGCS|PRIMEM" ); 1151 1152 return OGRERR_NONE; 1153 } 1154 1155 /************************************************************************/ 1156 /* importProjCSFromXML() */ 1157 /************************************************************************/ 1158 1159 static OGRErr importProjCSFromXML( OGRSpatialReference *poSRS, 1160 CPLXMLNode *psCRS ) 1161 1162 { 1163 /* -------------------------------------------------------------------- */ 1164 /* Setup the PROJCS node with a name. */ 1165 /* -------------------------------------------------------------------- */ 1166 poSRS->SetProjCS( CPLGetXMLValue( psCRS, "srsName", "Unnamed" ) ); 1167 1168 /* -------------------------------------------------------------------- */ 1169 /* Get authority information if available. If we got it, and */ 1170 /* we seem to be lacking inline definition values, try and */ 1171 /* define according to the EPSG code for the PCS. */ 1172 /* -------------------------------------------------------------------- */ 1173 importXMLAuthority( psCRS, poSRS, "srsID", "PROJCS" ); 1174 1175 if( poSRS->GetAuthorityCode( "PROJCS" ) != nullptr 1176 && poSRS->GetAuthorityName( "PROJCS" ) != nullptr 1177 && EQUAL(poSRS->GetAuthorityName("PROJCS"), "EPSG") 1178 && (CPLGetXMLNode( psCRS, "definedByConversion.Conversion" ) == nullptr 1179 || CPLGetXMLNode( psCRS, "baseCRS.GeographicCRS" ) == nullptr) ) 1180 { 1181 return poSRS->importFromEPSG( atoi(poSRS->GetAuthorityCode("PROJCS")) ); 1182 } 1183 1184 /* -------------------------------------------------------------------- */ 1185 /* Try to set the GEOGCS info. */ 1186 /* -------------------------------------------------------------------- */ 1187 1188 CPLXMLNode *psSubXML = CPLGetXMLNode( psCRS, "baseCRS.GeographicCRS" ); 1189 if( psSubXML != nullptr ) 1190 { 1191 const OGRErr eErr = importGeogCSFromXML( poSRS, psSubXML ); 1192 if( eErr != OGRERR_NONE ) 1193 return eErr; 1194 } 1195 1196 /* -------------------------------------------------------------------- */ 1197 /* Get the conversion node. It should be the only child of the */ 1198 /* definedByConversion node. */ 1199 /* -------------------------------------------------------------------- */ 1200 CPLXMLNode *psConv = CPLGetXMLNode(psCRS, "definedByConversion.Conversion"); 1201 if( psConv == nullptr || psConv->eType != CXT_Element ) 1202 { 1203 CPLError( CE_Failure, CPLE_AppDefined, 1204 "Unable to find a conversion node under the " 1205 "definedByConversion node of the ProjectedCRS." ); 1206 return OGRERR_CORRUPT_DATA; 1207 } 1208 1209 /* -------------------------------------------------------------------- */ 1210 /* Determine the conversion method in effect. */ 1211 /* -------------------------------------------------------------------- */ 1212 const int nMethod = 1213 getEPSGObjectCodeValue( CPLGetXMLNode( psConv, "usesMethod"), 1214 "method", 0 ); 1215 1216 /* -------------------------------------------------------------------- */ 1217 /* Transverse Mercator. */ 1218 /* -------------------------------------------------------------------- */ 1219 if( nMethod == 9807 ) 1220 { 1221 poSRS->SetTM( 1222 getProjectionParam( psConv, 8801, "Angular", 0.0 ), 1223 getProjectionParam( psConv, 8802, "Angular", 0.0 ), 1224 getProjectionParam( psConv, 8805, "Unitless", 1.0 ), 1225 getProjectionParam( psConv, 8806, "Linear", 0.0 ), 1226 getProjectionParam( psConv, 8807, "Linear", 0.0 ) ); 1227 } 1228 1229 /* -------------------------------------------------------------------- */ 1230 /* Didn't recognise? */ 1231 /* -------------------------------------------------------------------- */ 1232 else 1233 { 1234 CPLError( CE_Failure, CPLE_AppDefined, 1235 "Conversion method %d not recognised.", 1236 nMethod ); 1237 return OGRERR_CORRUPT_DATA; 1238 } 1239 1240 // Re-set authority as all editions above will have removed it 1241 importXMLAuthority( psCRS, poSRS, "srsID", "PROJCS" ); 1242 1243 // Need to get linear units here! 1244 1245 return OGRERR_NONE; 1246 } 1247 1248 /************************************************************************/ 1249 /* importFromXML() */ 1250 /************************************************************************/ 1251 1252 /** 1253 * \brief Import coordinate system from XML format (GML only currently). 1254 * 1255 * This method is the same as the C function OSRImportFromXML() 1256 * @param pszXML XML string to import 1257 * @return OGRERR_NONE on success or OGRERR_CORRUPT_DATA on failure. 1258 */ 1259 OGRErr OGRSpatialReference::importFromXML( const char *pszXML ) 1260 1261 { 1262 Clear(); 1263 1264 /* -------------------------------------------------------------------- */ 1265 /* Parse the XML. */ 1266 /* -------------------------------------------------------------------- */ 1267 CPLXMLNode *psTree = CPLParseXMLString( pszXML ); 1268 1269 if( psTree == nullptr ) 1270 return OGRERR_CORRUPT_DATA; 1271 1272 CPLStripXMLNamespace( psTree, "gml", TRUE ); 1273 1274 /* -------------------------------------------------------------------- */ 1275 /* Import according to the root node type. We walk through */ 1276 /* root elements as there is sometimes prefix stuff like */ 1277 /* <?xml>. */ 1278 /* -------------------------------------------------------------------- */ 1279 OGRErr eErr = OGRERR_UNSUPPORTED_SRS; 1280 1281 for( CPLXMLNode* psNode = psTree; psNode != nullptr; psNode = psNode->psNext ) 1282 { 1283 if( EQUAL(psNode->pszValue, "GeographicCRS") ) 1284 { 1285 eErr = importGeogCSFromXML( this, psNode ); 1286 break; 1287 } 1288 1289 else if( EQUAL(psNode->pszValue, "ProjectedCRS") ) 1290 { 1291 eErr = importProjCSFromXML( this, psNode ); 1292 break; 1293 } 1294 } 1295 1296 CPLDestroyXMLNode( psTree ); 1297 1298 return eErr; 1299 } 1300 1301 /************************************************************************/ 1302 /* OSRImportFromXML() */ 1303 /************************************************************************/ 1304 1305 /** 1306 * \brief Import coordinate system from XML format (GML only currently). 1307 * 1308 * This function is the same as OGRSpatialReference::importFromXML(). 1309 */ 1310 OGRErr OSRImportFromXML( OGRSpatialReferenceH hSRS, const char *pszXML ) 1311 1312 { 1313 VALIDATE_POINTER1( hSRS, "OSRImportFromXML", OGRERR_FAILURE ); 1314 VALIDATE_POINTER1( pszXML, "OSRImportFromXML", OGRERR_FAILURE ); 1315 1316 return OGRSpatialReference::FromHandle(hSRS)->importFromXML( pszXML ); 1317 } 1318