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