/src/bag/api/bag_metadata_import.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //************************************************************************ |
2 | | // |
3 | | // Open Navigation Surface Working Group, 2013 |
4 | | // |
5 | | //************************************************************************ |
6 | | #include "bag_errors.h" |
7 | | #include "bag_legacy_crs.h" |
8 | | #include "bag_metadata_import.h" |
9 | | #include "bag_metadatatypes.h" |
10 | | |
11 | | #include <cstring> |
12 | | #include <iostream> |
13 | | #include <libxml/parser.h> |
14 | | #include <libxml/xmlschemas.h> |
15 | | #include <libxml/xpath.h> |
16 | | #include <libxml/xpathInternals.h> |
17 | | #include <sstream> |
18 | | #include <string> |
19 | | #include <sys/stat.h> |
20 | | #include <sys/types.h> |
21 | | #include <vector> |
22 | | |
23 | | |
24 | | namespace { |
25 | | |
26 | | //! The location of the BAG home folder. |
27 | | static std::string bagHomeFolder; |
28 | | |
29 | | //! The relative path from the BAG home folder, to the Bag schema file. |
30 | | static std::string ons_schema_location = "ISO19139/bag/bag.xsd"; |
31 | | |
32 | | //! Utility class to convert an encoded XML string. |
33 | | class EncodedString final |
34 | | { |
35 | | public: |
36 | | //************************************************************************ |
37 | | //! Constructor |
38 | | /*! |
39 | | \param doc |
40 | | \li The XML document that the string is from. |
41 | | \param string |
42 | | \li The string to be converted. |
43 | | */ |
44 | | //************************************************************************ |
45 | | EncodedString(xmlDoc& doc, const char* string) noexcept |
46 | 20.6k | { |
47 | 20.6k | this->m_pEncodedString = xmlEncodeEntitiesReentrant(&doc, |
48 | 20.6k | reinterpret_cast<const xmlChar*>(string)); |
49 | 20.6k | } |
50 | | |
51 | | EncodedString(const EncodedString&) = delete; |
52 | | EncodedString(EncodedString&&) = delete; |
53 | | EncodedString& operator=(const EncodedString&) = delete; |
54 | | EncodedString& operator=(EncodedString&&) = delete; |
55 | | |
56 | | //************************************************************************ |
57 | | //! Destructor. |
58 | | //************************************************************************ |
59 | | ~EncodedString() noexcept |
60 | 20.6k | { |
61 | 20.6k | xmlFree(this->m_pEncodedString); |
62 | 20.6k | } |
63 | | |
64 | | //************************************************************************ |
65 | | //! Conversion operator. |
66 | | /*! |
67 | | \return |
68 | | \li The encoded string. |
69 | | */ |
70 | | //************************************************************************ |
71 | | operator xmlChar*() const noexcept |
72 | 20.6k | { |
73 | 20.6k | return this->m_pEncodedString; |
74 | 20.6k | } |
75 | | |
76 | | private: |
77 | | //! The encoded string. |
78 | | xmlChar* m_pEncodedString = nullptr; |
79 | | }; |
80 | | |
81 | | //************************************************************************ |
82 | | //! Convert a string to a double value. |
83 | | /*! |
84 | | \param value |
85 | | \li The input string to be converted. |
86 | | \return |
87 | | \li The double value. |
88 | | */ |
89 | | //************************************************************************ |
90 | | double toDouble(const std::string& value) |
91 | 1.37k | { |
92 | 1.37k | std::stringstream lineStream; |
93 | 1.37k | (void)lineStream.imbue(std::locale::classic()); |
94 | 1.37k | lineStream << value; |
95 | | |
96 | 1.37k | double dblValue = 0.0; |
97 | 1.37k | lineStream >> dblValue; |
98 | | |
99 | 1.37k | return dblValue; |
100 | 1.37k | } |
101 | | |
102 | | //************************************************************************ |
103 | | //! Get the name of a node. |
104 | | /*! |
105 | | \param value |
106 | | \li The input string to be converted. |
107 | | \return |
108 | | \li The node name. |
109 | | */ |
110 | | //************************************************************************ |
111 | | std::string getNodeName(const xmlNode& node) |
112 | 284 | { |
113 | 284 | std::string name; |
114 | | |
115 | | // append the namespace prefix |
116 | 284 | const xmlNs* nameSpace = node.ns; |
117 | 284 | if (nameSpace) |
118 | 284 | { |
119 | 284 | name = reinterpret_cast<const char*>(nameSpace->prefix); |
120 | 284 | name += ':'; |
121 | 284 | } |
122 | | |
123 | 284 | name += reinterpret_cast<const char*>(node.name); |
124 | | |
125 | 284 | return name; |
126 | 284 | } |
127 | | |
128 | | //************************************************************************ |
129 | | //! Find all the nodes matching the supplied xpath pattern. |
130 | | /*! |
131 | | \param relativeNode |
132 | | \li The node to start searching from. |
133 | | \param searchString |
134 | | \li The pattern to be searched for. The string conforms to the xpath |
135 | | searching syntax. For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp |
136 | | \return |
137 | | \li The list of XML nodes that match \e searchString |
138 | | */ |
139 | | //************************************************************************ |
140 | | std::vector<xmlNode*> findNodes( |
141 | | xmlNode& relativeNode, |
142 | | const char* searchString) |
143 | 20.4k | { |
144 | | //Get the root node of the document. |
145 | 20.4k | const xmlNode* pRoot = xmlDocGetRootElement(relativeNode.doc); |
146 | 20.4k | if (!pRoot) |
147 | 0 | return {}; |
148 | | |
149 | | //If the xPath context has not been initialized yet, do it now. |
150 | 20.4k | xmlXPathContext* pContext = xmlXPathNewContext(relativeNode.doc); |
151 | 20.4k | if (!pContext) |
152 | 0 | return {}; |
153 | | |
154 | 20.4k | pContext->node = &relativeNode; |
155 | | |
156 | | //Register any namespaces with the xPath context. |
157 | 20.4k | const xmlNs* xmlNameSpace = pRoot->nsDef; |
158 | | |
159 | 162k | while (xmlNameSpace) |
160 | 141k | { |
161 | 141k | if (xmlNameSpace->prefix) |
162 | 141k | { |
163 | 141k | const int ret = xmlXPathRegisterNs(pContext, xmlNameSpace->prefix, |
164 | 141k | xmlNameSpace->href); |
165 | 141k | if (ret != 0) |
166 | 0 | { |
167 | | //Error |
168 | 0 | xmlXPathFreeContext(pContext); |
169 | 0 | return {}; |
170 | 0 | } |
171 | 141k | } |
172 | | |
173 | 141k | xmlNameSpace = xmlNameSpace->next; |
174 | 141k | } |
175 | | |
176 | | //Encode the specified search string. |
177 | 20.4k | const EncodedString encodedSearch{*relativeNode.doc, searchString}; |
178 | | |
179 | | //Evaluate the expression. |
180 | 20.4k | xmlXPathObject* pPathObject = xmlXPathEvalExpression(encodedSearch, pContext); |
181 | 20.4k | if (!pPathObject) |
182 | 2.82k | { |
183 | | //Error |
184 | 2.82k | xmlXPathFreeContext(pContext); |
185 | 2.82k | return {}; |
186 | 2.82k | } |
187 | | |
188 | 17.6k | std::vector<xmlNode*> retList; |
189 | | |
190 | | //Add each value that was returned. |
191 | 17.6k | if (pPathObject->nodesetval) |
192 | 15.8k | { |
193 | 15.8k | retList.reserve(pPathObject->nodesetval->nodeNr); |
194 | | |
195 | 31.3k | for (int i = 0; i < pPathObject->nodesetval->nodeNr; i++) |
196 | 15.5k | retList.push_back(pPathObject->nodesetval->nodeTab[i]); |
197 | 15.8k | } |
198 | | |
199 | 17.6k | xmlXPathFreeObject(pPathObject); |
200 | 17.6k | xmlXPathFreeContext(pContext); |
201 | | |
202 | 17.6k | return retList; |
203 | 20.4k | } |
204 | | |
205 | | //************************************************************************ |
206 | | //! Find a single node matching the given xpath pattern. |
207 | | /*! |
208 | | \param relativeNode |
209 | | \li The node to start searching from. |
210 | | \param searchString |
211 | | \li The pattern to be searched for. The string conforms to the xpath |
212 | | searching syntax. For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp |
213 | | \return |
214 | | \li The first XML node that matches \e searchString |
215 | | */ |
216 | | //************************************************************************ |
217 | | xmlNode* findNode( |
218 | | xmlNode& relativeNode, |
219 | | const char* searchString) |
220 | 19.0k | { |
221 | 19.0k | auto retList = findNodes(relativeNode, searchString); |
222 | 19.0k | if (retList.empty()) |
223 | 4.78k | return nullptr; |
224 | | |
225 | 14.2k | return retList.front(); |
226 | 19.0k | } |
227 | | |
228 | | //************************************************************************ |
229 | | //! Get the named property from an XML node. |
230 | | /*! |
231 | | \param current |
232 | | \li The node to retrieve the property from. |
233 | | \param propertyName |
234 | | \li The name of the property to be retrieved. |
235 | | \return |
236 | | \li The property matching \e propertyName from \e current. |
237 | | */ |
238 | | //************************************************************************ |
239 | | std::string getProperty( |
240 | | const xmlNode& current, |
241 | | const char* propertyName) |
242 | 189 | { |
243 | | // Retrieve the property. |
244 | 189 | xmlChar* temp = xmlGetProp(¤t, EncodedString{*current.doc, |
245 | 189 | propertyName}); |
246 | 189 | if (!temp) |
247 | 4 | return {}; |
248 | | |
249 | 185 | const std::string value(reinterpret_cast<char*>(temp)); |
250 | | |
251 | | // Free the memory allocated by xmlGetProp(). |
252 | 185 | xmlFree(temp); |
253 | | |
254 | 185 | return value; |
255 | 189 | } |
256 | | |
257 | | //************************************************************************ |
258 | | //! Get the contents of an XML node. |
259 | | /*! |
260 | | \param current |
261 | | \li The node to retrieve the contents from. |
262 | | \return |
263 | | \li The contents of \e current. |
264 | | */ |
265 | | //************************************************************************ |
266 | | std::string getContents(const xmlNode& current) |
267 | 11.8k | { |
268 | 11.8k | std::string contents; |
269 | | |
270 | | // Get the children of the current element. |
271 | 11.8k | const xmlNode* text = current.children; |
272 | | |
273 | | // Concatenate all the text elements. |
274 | 23.7k | while (text) |
275 | 11.9k | { |
276 | 11.9k | if (text->type == XML_TEXT_NODE && text->content) |
277 | 11.8k | contents += reinterpret_cast<const char*>(text->content); |
278 | | |
279 | 11.9k | text = text->next; |
280 | 11.9k | } |
281 | | |
282 | 11.8k | return contents; |
283 | 11.8k | } |
284 | | |
285 | | //************************************************************************ |
286 | | //! Get the named property from an XML node as a string. |
287 | | /*! |
288 | | \param node |
289 | | \li The node to begin searching from. |
290 | | \param searchPath |
291 | | \li The pattern to be searched for. The string conforms to the xpath |
292 | | searching syntax. For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp |
293 | | \param propertyName |
294 | | \li The name of the property to be retrieved from the node matching |
295 | | \e searchPath |
296 | | \return |
297 | | \li The specified property as a string value. NULL is returned if |
298 | | a node matching \e searchPath cannot be found. |
299 | | */ |
300 | | //************************************************************************ |
301 | | char* getPropertyAsString( |
302 | | xmlNode& node, |
303 | | const char* searchPath, |
304 | | const char* propertyName) |
305 | 284 | { |
306 | 284 | const xmlNode* pNode = findNode(node, searchPath); |
307 | 284 | if (!pNode) |
308 | 95 | return nullptr; |
309 | | |
310 | 189 | const std::string value = getProperty(*pNode, propertyName); |
311 | | |
312 | 189 | char* result = new char[value.size() + 1]; |
313 | 189 | strcpy(result, value.c_str()); |
314 | 189 | result[value.size()] = '\0'; |
315 | | |
316 | 189 | return result; |
317 | | |
318 | 284 | } |
319 | | |
320 | | //************************************************************************ |
321 | | //! Get the contents of an XML node as a string. |
322 | | /*! |
323 | | \param node |
324 | | \li The node to begin searching from. |
325 | | \param searchPath |
326 | | \li The pattern to be searched for. The string conforms to the xpath |
327 | | searching syntax. For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp |
328 | | \return |
329 | | \li The contents of \e node as a string value. NULL is returned if |
330 | | a node matching \e searchPath cannot be found. |
331 | | */ |
332 | | //************************************************************************ |
333 | | std::string getContentsAsString( |
334 | | xmlNode& node, |
335 | | const char* searchPath) |
336 | 13.3k | { |
337 | 13.3k | const xmlNode* pNode = findNode(node, searchPath); |
338 | 13.3k | if (!pNode) |
339 | 3.77k | return {}; |
340 | | |
341 | 9.59k | return getContents(*pNode); |
342 | 13.3k | } |
343 | | |
344 | | char* copyString(const char* source) |
345 | 13.3k | { |
346 | 13.3k | if (!source || strlen(source) == 0) |
347 | 3.77k | return nullptr; |
348 | | |
349 | 9.59k | char* result = new char[strlen(source) + 1]; |
350 | 9.59k | strcpy(result, source); |
351 | | |
352 | 9.59k | return result; |
353 | 13.3k | } |
354 | | |
355 | | char* getContentsAsCharStar( |
356 | | xmlNode& node, |
357 | | const char* searchPath) |
358 | 13.3k | { |
359 | 13.3k | return copyString(getContentsAsString(node, searchPath).c_str()); |
360 | 13.3k | } |
361 | | |
362 | | //************************************************************************ |
363 | | //! Get the contents of an XML node as an integer. |
364 | | /*! |
365 | | \param node |
366 | | \li The node to begin searching from. |
367 | | \param searchPath |
368 | | \li The pattern to be searched for. The string conforms to the xpath |
369 | | searching syntax. For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp |
370 | | \return |
371 | | \li The contents of \e node as an integer value. 0 is returned if |
372 | | a node matching \e searchPath cannot be found. |
373 | | */ |
374 | | //************************************************************************ |
375 | | int32_t getContentsAsInt( |
376 | | xmlNode& node, |
377 | | const char* searchPath) |
378 | 568 | { |
379 | 568 | auto* pNode = findNode(node, searchPath); |
380 | 568 | if (!pNode) |
381 | 177 | return 0; |
382 | | |
383 | 391 | return static_cast<int32_t>(toDouble(getContents(*pNode))); |
384 | 568 | } |
385 | | |
386 | | //************************************************************************ |
387 | | //! Get the contents of an XML node as a 64 bit floating point value. |
388 | | /*! |
389 | | \param node |
390 | | \li The node to begin searching from. |
391 | | \param searchPath |
392 | | \li The pattern to be searched for. The string conforms to the xpath |
393 | | searching syntax. For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp |
394 | | \return |
395 | | \li The contents of \e node as a 64 bit floating point value. |
396 | | 0.0 is returned if a node matching \e searchPath cannot be found. |
397 | | */ |
398 | | //************************************************************************ |
399 | | double getContentsAsFloat( |
400 | | xmlNode& node, |
401 | | const char* searchPath) |
402 | 1.70k | { |
403 | 1.70k | const xmlNode* pNode = findNode(node, searchPath); |
404 | 1.70k | if (!pNode) |
405 | 719 | return 0.0; |
406 | | |
407 | 985 | return toDouble(getContents(*pNode)); |
408 | 1.70k | } |
409 | | |
410 | | //************************************************************************ |
411 | | //! Get the contents of an XML node as a boolean value. |
412 | | /*! |
413 | | \param node |
414 | | \li The node to begin searching from. |
415 | | \param searchPath |
416 | | \li The pattern to be searched for. The string conforms to the xpath |
417 | | searching syntax. For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp |
418 | | \return |
419 | | \li The contents of \e node as boolean value. False is returned if a node |
420 | | matching \e searchPath cannot be found. |
421 | | */ |
422 | | //************************************************************************ |
423 | | bool getContentsAsBool( |
424 | | xmlNode& node, |
425 | | const char* searchPath) |
426 | 568 | { |
427 | 568 | const xmlNode* pNode = findNode(node, searchPath); |
428 | 568 | if (!pNode) |
429 | 26 | return false; |
430 | | |
431 | 542 | const std::string value = getContents(*pNode); |
432 | | |
433 | | // Prevent repeated memory allocations. |
434 | 542 | static std::string kZero{"0"}; |
435 | 542 | static std::string kFalse{"false"}; |
436 | | |
437 | 542 | return (value != kZero && value != kFalse); |
438 | 568 | } |
439 | | |
440 | | } // namespace |
441 | | |
442 | | namespace BAG { |
443 | | |
444 | | //************************************************************************ |
445 | | //! Get the current setting for the BAG_HOME directory. |
446 | | /*! |
447 | | \return |
448 | | \li If the user has called bagSetHomeFolder(), then that |
449 | | value is returned, otherwise, getenv("BAG_HOME") is |
450 | | returned. |
451 | | */ |
452 | | //************************************************************************ |
453 | | std::string bagGetHomeFolder() |
454 | 0 | { |
455 | | //If the BAG home folder has been set, then return it. |
456 | 0 | if (!bagHomeFolder.empty()) |
457 | 0 | return bagHomeFolder; |
458 | | |
459 | | //Else we will return the environment variable. |
460 | 0 | const char* bagHome = getenv("BAG_HOME"); |
461 | 0 | if (bagHome) |
462 | 0 | return std::string{bagHome}; |
463 | | |
464 | 0 | return {}; |
465 | 0 | } |
466 | | |
467 | | //************************************************************************ |
468 | | //! Set the location of the BAG 'home' directory. |
469 | | /*! |
470 | | \param homeFolder |
471 | | \li The new location for the BAG home directory. |
472 | | */ |
473 | | //************************************************************************ |
474 | | void bagSetHomeFolder(const char* homeFolder) |
475 | 0 | { |
476 | 0 | bagHomeFolder = homeFolder; |
477 | 0 | } |
478 | | |
479 | | //************************************************************************ |
480 | | //! Decode a BagResponsibleParty from the supplied XML node. |
481 | | /*! |
482 | | \param node |
483 | | \li The XML node containing the responsible party information. |
484 | | \param responsibleParty |
485 | | \li Modified to contain the responsible party information from \e node. |
486 | | \param schemaVersion |
487 | | \li The version of the schema stored in \e node. |
488 | | \return |
489 | | \li True if the information was found and decoded properly, False if |
490 | | an error occurs. |
491 | | */ |
492 | | //************************************************************************ |
493 | | bool decodeResponsibleParty( |
494 | | xmlNode& node, |
495 | | BagResponsibleParty& responsibleParty, |
496 | | uint16_t schemaVersion) |
497 | 717 | { |
498 | 717 | if (schemaVersion == 1) |
499 | 0 | { |
500 | | //smXML:CI_ResponsibleParty/individualName |
501 | 0 | responsibleParty.individualName = getContentsAsCharStar(node, |
502 | 0 | "smXML:CI_ResponsibleParty/individualName"); |
503 | | |
504 | | //smXML:CI_ResponsibleParty/organisationName |
505 | 0 | responsibleParty.organisationName = getContentsAsCharStar(node, |
506 | 0 | "smXML:CI_ResponsibleParty/organisationName"); |
507 | | |
508 | | //smXML:CI_ResponsibleParty/positionName |
509 | 0 | responsibleParty.positionName = getContentsAsCharStar(node, |
510 | 0 | "smXML:CI_ResponsibleParty/positionName"); |
511 | | |
512 | | //smXML:CI_ResponsibleParty/role |
513 | 0 | responsibleParty.role = getContentsAsCharStar(node, |
514 | 0 | "smXML:CI_ResponsibleParty/role"); |
515 | 0 | } |
516 | 717 | else if (schemaVersion == 2) |
517 | 717 | { |
518 | | //gmd:CI_ResponsibleParty/gmd:individualName |
519 | 717 | responsibleParty.individualName = getContentsAsCharStar(node, |
520 | 717 | "gmd:CI_ResponsibleParty/gmd:individualName/gco:CharacterString"); |
521 | | |
522 | | //gmd:CI_ResponsibleParty/gmd:organisationName |
523 | 717 | responsibleParty.organisationName = getContentsAsCharStar(node, |
524 | 717 | "gmd:CI_ResponsibleParty/gmd:organisationName/gco:CharacterString"); |
525 | | |
526 | | //gmd:CI_ResponsibleParty/gmd:positionName |
527 | 717 | responsibleParty.positionName = getContentsAsCharStar(node, |
528 | 717 | "gmd:CI_ResponsibleParty/gmd:positionName/gco:CharacterString"); |
529 | | |
530 | | //gmd:CI_ResponsibleParty/gmd:role |
531 | 717 | responsibleParty.role = getContentsAsCharStar(node, |
532 | 717 | "gmd:CI_ResponsibleParty/gmd:role/gmd:CI_RoleCode"); |
533 | 717 | } |
534 | | |
535 | 717 | return true; |
536 | 717 | } |
537 | | |
538 | | //************************************************************************ |
539 | | //! Decode a BagLegalConstraints from the supplied XML node. |
540 | | /*! |
541 | | \param node |
542 | | \li The XML node containing the legal constraints information. |
543 | | \param legalConstraints |
544 | | \li Modified to contain the legal constraints information from \e node. |
545 | | \param schemaVersion |
546 | | \li The version of the schema stored in \e node. |
547 | | \return |
548 | | \li True if the information was found and decoded properly, False if |
549 | | an error occurs. |
550 | | */ |
551 | | //************************************************************************ |
552 | | bool decodeLegalConstraints( |
553 | | xmlNode& node, |
554 | | BagLegalConstraints& legalConstraints, |
555 | | uint16_t schemaVersion) |
556 | 284 | { |
557 | 284 | if (schemaVersion == 1) |
558 | 0 | { |
559 | | //smXML:MD_LegalConstraints/useConstraints |
560 | 0 | legalConstraints.useConstraints = getContentsAsCharStar(node, |
561 | 0 | "smXML:MD_LegalConstraints/useConstraints"); |
562 | | |
563 | | //smXML:MD_LegalConstraints/otherConstraints |
564 | 0 | legalConstraints.otherConstraints = getContentsAsCharStar(node, |
565 | 0 | "smXML:MD_LegalConstraints/otherConstraints"); |
566 | 0 | } |
567 | 284 | else if (schemaVersion == 2) |
568 | 284 | { |
569 | | //gmd:MD_LegalConstraints/gmd:useConstraints |
570 | 284 | legalConstraints.useConstraints = getContentsAsCharStar(node, |
571 | 284 | "gmd:MD_LegalConstraints/gmd:useConstraints/gmd:MD_RestrictionCode"); |
572 | | |
573 | | //gmd:MD_LegalConstraints/gmd:otherConstraints |
574 | 284 | legalConstraints.otherConstraints = getContentsAsCharStar(node, |
575 | 284 | "gmd:MD_LegalConstraints/gmd:otherConstraints/gco:CharacterString"); |
576 | 284 | } |
577 | | |
578 | 284 | return true; |
579 | 284 | } |
580 | | |
581 | | //************************************************************************ |
582 | | //! Decode a BagSecurityConstraints from the supplied XML node. |
583 | | /*! |
584 | | \param node |
585 | | \li The XML node containing the security constraints information. |
586 | | \param securityConstraints |
587 | | \li Modified to contain the security constraints information from \e node. |
588 | | \param schemaVersion |
589 | | \li The version of the schema stored in \e node. |
590 | | \return |
591 | | \li True if the information was found and decoded properly, False if |
592 | | an error occurs. |
593 | | */ |
594 | | //************************************************************************ |
595 | | bool decodeSecurityConstraints( |
596 | | xmlNode& node, |
597 | | BagSecurityConstraints& securityConstraints, |
598 | | uint16_t schemaVersion) |
599 | 284 | { |
600 | 284 | if (schemaVersion == 1) |
601 | 0 | { |
602 | | //smXML:MD_SecurityConstraints/classification |
603 | 0 | securityConstraints.classification = getContentsAsCharStar(node, |
604 | 0 | "smXML:MD_SecurityConstraints/classification"); |
605 | | |
606 | | //smXML:MD_SecurityConstraints/userNote |
607 | 0 | securityConstraints.userNote = getContentsAsCharStar(node, |
608 | 0 | "smXML:MD_SecurityConstraints/userNote"); |
609 | 0 | } |
610 | 284 | else if (schemaVersion == 2) |
611 | 284 | { |
612 | | //gmd:MD_SecurityConstraints/gmd:classification |
613 | 284 | securityConstraints.classification = getContentsAsCharStar(node, |
614 | 284 | "gmd:MD_SecurityConstraints/gmd:classification/gmd:MD_ClassificationCode"); |
615 | | |
616 | | //gmd:MD_SecurityConstraints/gmd:userNote |
617 | 284 | securityConstraints.userNote = getContentsAsCharStar(node, |
618 | 284 | "gmd:MD_SecurityConstraints/gmd:userNote/gco:CharacterString"); |
619 | 284 | } |
620 | | |
621 | 284 | return true; |
622 | 284 | } |
623 | | |
624 | | //************************************************************************ |
625 | | //! Decode a BagSource from the supplied XML node. |
626 | | /*! |
627 | | \param node |
628 | | \li The XML node containing the source information. |
629 | | \param sourceInfo |
630 | | \li Modified to contain the source information from \e node. |
631 | | \param schemaVersion |
632 | | \li The version of the schema stored in \e node. |
633 | | \return |
634 | | \li True if the information was found and decoded properly, False if |
635 | | an error occurs. |
636 | | */ |
637 | | //************************************************************************ |
638 | | bool decodeSourceInfo( |
639 | | xmlNode& node, |
640 | | BagSource& sourceInfo, |
641 | | uint16_t schemaVersion) |
642 | 283 | { |
643 | 283 | if (schemaVersion == 1) |
644 | 0 | { |
645 | | //smXML:LI_Source/description |
646 | 0 | sourceInfo.description = getContentsAsCharStar(node, |
647 | 0 | "smXML:LI_Source/description"); |
648 | 0 | } |
649 | 283 | else if (schemaVersion == 2) |
650 | 283 | { |
651 | | //gmd:LI_Source/gmd:description |
652 | 283 | sourceInfo.description = getContentsAsCharStar(node, |
653 | 283 | "gmd:LI_Source/gmd:description/gco:CharacterString"); |
654 | | |
655 | | //gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:title |
656 | 283 | sourceInfo.title = getContentsAsCharStar(node, |
657 | 283 | "gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:title/gco:CharacterString"); |
658 | | |
659 | | //gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:CI_Date/gmd:date |
660 | 283 | sourceInfo.date = getContentsAsCharStar(node, |
661 | 283 | "gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:date/gmd:CI_Date/gmd:date/gco:Date"); |
662 | | |
663 | | //gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:CI_Date/gmd:dateType |
664 | 283 | sourceInfo.dateType = getContentsAsCharStar(node, |
665 | 283 | "gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:date/gmd:CI_Date/gmd:dateType/gmd:CI_DateTypeCode"); |
666 | | |
667 | | //gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:citedResponsibleParty |
668 | 283 | const auto partyNodes = findNodes(node, |
669 | 283 | "gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:citedResponsibleParty"); |
670 | 283 | if (!partyNodes.empty()) |
671 | 0 | { |
672 | 0 | sourceInfo.numberOfResponsibleParties = |
673 | 0 | static_cast<uint32_t>(partyNodes.size()); |
674 | 0 | sourceInfo.responsibleParties = new BagResponsibleParty[sourceInfo.numberOfResponsibleParties]; |
675 | |
|
676 | 0 | for (uint32_t i = 0; i < sourceInfo.numberOfResponsibleParties; i++) |
677 | 0 | { |
678 | 0 | initResponsibleParty(sourceInfo.responsibleParties[i]); |
679 | 0 | if (!decodeResponsibleParty(*partyNodes[i], |
680 | 0 | sourceInfo.responsibleParties[i], schemaVersion)) |
681 | 0 | return false; |
682 | 0 | } |
683 | 0 | } |
684 | 283 | } |
685 | | |
686 | 283 | return true; |
687 | 283 | } |
688 | | |
689 | | //************************************************************************ |
690 | | //! Decode a BagProcessStep from the supplied XML node. |
691 | | /*! |
692 | | \param node |
693 | | \li The XML node containing the process information. |
694 | | \param processStep |
695 | | \li Modified to contain the process information from \e node. |
696 | | \param schemaVersion |
697 | | \li The version of the schema stored in \e node. |
698 | | \return |
699 | | \li True if the information was found and decoded properly, False if |
700 | | an error occurs. |
701 | | */ |
702 | | //************************************************************************ |
703 | | bool decodeProcessStep( |
704 | | xmlNode& node, |
705 | | BagProcessStep& processStep, |
706 | | uint16_t schemaVersion) |
707 | 283 | { |
708 | 283 | if (schemaVersion == 1) |
709 | 0 | { |
710 | | //smXML:BAG_ProcessStep/description |
711 | 0 | processStep.description = getContentsAsCharStar(node, |
712 | 0 | "smXML:BAG_ProcessStep/description"); |
713 | | |
714 | | //smXML:BAG_ProcessStep/dateTime |
715 | 0 | processStep.dateTime = getContentsAsCharStar(node, |
716 | 0 | "smXML:BAG_ProcessStep/dateTime"); |
717 | | |
718 | | //smXML:BAG_ProcessStep/trackingId |
719 | 0 | processStep.trackingId = getContentsAsCharStar(node, |
720 | 0 | "smXML:BAG_ProcessStep/trackingId"); |
721 | | |
722 | | //smXML:BAG_ProcessStep/processor |
723 | 0 | const auto processorNodes = findNodes(node, |
724 | 0 | "smXML:BAG_ProcessStep/processor"); |
725 | 0 | if (!processorNodes.empty()) |
726 | 0 | { |
727 | 0 | processStep.numberOfProcessors = |
728 | 0 | static_cast<uint32_t>(processorNodes.size()); |
729 | 0 | processStep.processors = |
730 | 0 | new BagResponsibleParty[processStep.numberOfProcessors]; |
731 | |
|
732 | 0 | for (uint32_t i = 0; i < processStep.numberOfProcessors; i++) |
733 | 0 | { |
734 | 0 | initResponsibleParty(processStep.processors[i]); |
735 | 0 | if (!decodeResponsibleParty(*processorNodes[i], |
736 | 0 | processStep.processors[i], schemaVersion)) |
737 | 0 | return false; |
738 | 0 | } |
739 | 0 | } |
740 | | |
741 | | //Sources are stored at the same level as the process step, so go up a level. |
742 | 0 | const auto sourceNodes = findNodes(node, |
743 | 0 | "parent::*/source"); |
744 | 0 | if (!sourceNodes.empty()) |
745 | 0 | { |
746 | 0 | processStep.numberOfSources = |
747 | 0 | static_cast<uint32_t>(sourceNodes.size()); |
748 | 0 | processStep.lineageSources = |
749 | 0 | new BagSource[processStep.numberOfSources]; |
750 | |
|
751 | 0 | for (uint32_t i = 0; i < processStep.numberOfSources; i++) |
752 | 0 | { |
753 | 0 | initSourceInfo(processStep.lineageSources[i]); |
754 | 0 | if (!decodeSourceInfo(*sourceNodes[i], |
755 | 0 | processStep.lineageSources[i], schemaVersion)) |
756 | 0 | return false; |
757 | 0 | } |
758 | 0 | } |
759 | 0 | } |
760 | 283 | else if (schemaVersion == 2) |
761 | 283 | { |
762 | | //bag:BAG_ProcessStep/gmd:description |
763 | 283 | processStep.description = getContentsAsCharStar(node, |
764 | 283 | "//gmd:description/gco:CharacterString"); |
765 | | |
766 | | //bag:BAG_ProcessStep/gmd:dateTime |
767 | 283 | processStep.dateTime = getContentsAsCharStar(node, |
768 | 283 | "//gmd:dateTime/gco:DateTime"); |
769 | | |
770 | | //bag:BAG_ProcessStep/bag:trackingId |
771 | 283 | processStep.trackingId = getContentsAsCharStar(node, |
772 | 283 | "//bag:trackingId/gco:CharacterString"); |
773 | | |
774 | | //bag:BAG_ProcessStep/gmd:processor |
775 | 283 | const auto processorNodes = findNodes(node, |
776 | 283 | "//gmd:processor"); |
777 | 283 | if (!processorNodes.empty()) |
778 | 283 | { |
779 | 283 | processStep.numberOfProcessors = |
780 | 283 | static_cast<uint32_t>(processorNodes.size()); |
781 | 283 | processStep.processors = |
782 | 283 | new BagResponsibleParty[processStep.numberOfProcessors]; |
783 | | |
784 | 566 | for (uint32_t i = 0; i < processStep.numberOfProcessors; i++) |
785 | 283 | { |
786 | 283 | initResponsibleParty(processStep.processors[i]); |
787 | 283 | if (!decodeResponsibleParty(*processorNodes[i], |
788 | 283 | processStep.processors[i], schemaVersion)) |
789 | 0 | return false; |
790 | 283 | } |
791 | 283 | } |
792 | | |
793 | | //bag:BAG_ProcessStep/gmd:source |
794 | 283 | const auto sourceNodes = findNodes(node, "//gmd:source"); |
795 | 283 | if (!sourceNodes.empty()) |
796 | 283 | { |
797 | 283 | processStep.numberOfSources = |
798 | 283 | static_cast<uint32_t>(sourceNodes.size()); |
799 | 283 | processStep.lineageSources = |
800 | 283 | new BagSource[processStep.numberOfSources]; |
801 | | |
802 | 566 | for (uint32_t i = 0; i < processStep.numberOfSources; i++) |
803 | 283 | { |
804 | 283 | initSourceInfo(processStep.lineageSources[i]); |
805 | 283 | if (!decodeSourceInfo(*sourceNodes[i], |
806 | 283 | processStep.lineageSources[i], schemaVersion)) |
807 | 0 | return false; |
808 | 283 | } |
809 | 283 | } |
810 | 283 | } |
811 | | |
812 | 283 | return true; |
813 | 283 | } |
814 | | |
815 | | //************************************************************************ |
816 | | //! Decode a BagDataQuality from the supplied XML node. |
817 | | /*! |
818 | | \param node |
819 | | \li The XML node containing the data quality information. |
820 | | \param dataQualityInfo |
821 | | \li Modified to contain the data quality information from \e node. |
822 | | \param schemaVersion |
823 | | \li The version of the schema stored in \e node. |
824 | | \return |
825 | | \li True if the information was found and decoded properly, False if |
826 | | an error occurs. |
827 | | */ |
828 | | //************************************************************************ |
829 | | bool decodeDataQualityInfo( |
830 | | xmlNode& node, |
831 | | BagDataQuality& dataQualityInfo, |
832 | | uint16_t schemaVersion) |
833 | 284 | { |
834 | 284 | if (schemaVersion == 1) |
835 | 0 | { |
836 | | //smXML:DQ_DataQuality/scope/smXML:DQ_Scope/level |
837 | 0 | dataQualityInfo.scope = getContentsAsCharStar(node, |
838 | 0 | "smXML:DQ_DataQuality/scope/smXML:DQ_Scope/level"); |
839 | | |
840 | | //smXML:DQ_DataQuality/lineage/smXML:LI_Lineage/processStep |
841 | 0 | const auto stepNodes = findNodes(node, |
842 | 0 | "smXML:DQ_DataQuality/lineage/smXML:LI_Lineage/processStep"); |
843 | 0 | if (!stepNodes.empty()) |
844 | 0 | { |
845 | 0 | dataQualityInfo.numberOfProcessSteps = |
846 | 0 | static_cast<uint32_t>(stepNodes.size()); |
847 | 0 | dataQualityInfo.lineageProcessSteps = |
848 | 0 | new BagProcessStep[dataQualityInfo.numberOfProcessSteps]; |
849 | |
|
850 | 0 | for (uint32_t i = 0; i < dataQualityInfo.numberOfProcessSteps; i++) |
851 | 0 | { |
852 | 0 | initProcessStep(dataQualityInfo.lineageProcessSteps[i]); |
853 | 0 | if (!decodeProcessStep(*stepNodes[i], |
854 | 0 | dataQualityInfo.lineageProcessSteps[i], schemaVersion)) |
855 | 0 | return false; |
856 | 0 | } |
857 | 0 | } |
858 | 0 | } |
859 | 284 | else if (schemaVersion == 2) |
860 | 284 | { |
861 | | //gmd:DQ_DataQuality/gmd:scope/gmd:DQ_Scope/gmd:level |
862 | 284 | delete[] dataQualityInfo.scope; |
863 | 284 | dataQualityInfo.scope = getContentsAsCharStar(node, |
864 | 284 | "gmd:DQ_DataQuality/gmd:scope/gmd:DQ_Scope/gmd:level/gmd:MD_ScopeCode"); |
865 | | |
866 | | //gmd:DQ_DataQuality/gmd:lineage/gmd:LI_Lineage/gmd:processStep |
867 | 284 | const auto stepNodes = findNodes(node, |
868 | 284 | "gmd:DQ_DataQuality/gmd:lineage/gmd:LI_Lineage/gmd:processStep"); |
869 | 284 | if (!stepNodes.empty()) |
870 | 283 | { |
871 | 283 | dataQualityInfo.numberOfProcessSteps = |
872 | 283 | static_cast<uint32_t>(stepNodes.size()); |
873 | 283 | dataQualityInfo.lineageProcessSteps = |
874 | 283 | new BagProcessStep[dataQualityInfo.numberOfProcessSteps]; |
875 | | |
876 | 566 | for (uint32_t i = 0; i < dataQualityInfo.numberOfProcessSteps; i++) |
877 | 283 | { |
878 | 283 | initProcessStep(dataQualityInfo.lineageProcessSteps[i]); |
879 | 283 | if (!decodeProcessStep(*stepNodes[i], |
880 | 283 | dataQualityInfo.lineageProcessSteps[i], schemaVersion)) |
881 | 0 | return false; |
882 | 283 | } |
883 | 283 | } |
884 | 284 | } |
885 | | |
886 | 284 | return true; |
887 | 284 | } |
888 | | |
889 | | //************************************************************************ |
890 | | //! Decode a BagSpatialRepresentation from the supplied XML node. |
891 | | /*! |
892 | | \param node |
893 | | \li The XML node containing the spatial representation information. |
894 | | \param spatialRepresentationInfo |
895 | | \li Modified to contain the spatial representation information from \e node. |
896 | | \param schemaVersion |
897 | | \li The version of the schema stored in \e node. |
898 | | \return |
899 | | \li True if the information was found and decoded properly, False if |
900 | | an error occurs. |
901 | | */ |
902 | | //************************************************************************ |
903 | | bool decodeSpatialRepresentationInfo( |
904 | | xmlNode& node, |
905 | | BagSpatialRepresentation& spatialRepresentationInfo, |
906 | | uint16_t schemaVersion) |
907 | 284 | { |
908 | 284 | if (schemaVersion == 1) |
909 | 0 | { |
910 | | //smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension/dimensionSize |
911 | 0 | spatialRepresentationInfo.numberOfRows = getContentsAsInt(node, |
912 | 0 | "smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension[dimensionName='row']/dimensionSize"); |
913 | | |
914 | | //smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension/resolution/smXML:Measure |
915 | 0 | spatialRepresentationInfo.rowResolution = getContentsAsFloat(node, |
916 | 0 | "smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension[dimensionName='row']/resolution/smXML:Measure/smXML:value"); |
917 | | |
918 | | //smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension/dimensionSize |
919 | 0 | spatialRepresentationInfo.numberOfColumns = getContentsAsInt(node, |
920 | 0 | "smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension[dimensionName='column']/dimensionSize"); |
921 | | |
922 | | //smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension/resolution/smXML:Measure |
923 | 0 | spatialRepresentationInfo.columnResolution = getContentsAsFloat(node, |
924 | 0 | "smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension[dimensionName='column']/resolution/smXML:Measure/smXML:value"); |
925 | | |
926 | | //smXML:MD_Georectified/cellGeometry |
927 | 0 | spatialRepresentationInfo.cellGeometry = getContentsAsCharStar(node, |
928 | 0 | "smXML:MD_Georectified/cellGeometry"); |
929 | | |
930 | | //smXML:MD_Georectified/transformationParameterAvailability |
931 | 0 | spatialRepresentationInfo.transformationParameterAvailability = |
932 | 0 | getContentsAsBool(node, "smXML:MD_Georectified/transformationParameterAvailability"); |
933 | | |
934 | | //smXML:MD_Georectified/checkPointAvailability |
935 | 0 | spatialRepresentationInfo.checkPointAvailability = getContentsAsBool( |
936 | 0 | node, "smXML:MD_Georectified/checkPointAvailability"); |
937 | | |
938 | | //smXML:MD_Georectified/cornerPoints/gml:Point |
939 | 0 | { |
940 | 0 | const xmlNode* pNode = findNode(node, |
941 | 0 | "smXML:MD_Georectified/cornerPoints/gml:Point/gml:coordinates"); |
942 | 0 | if (!pNode) |
943 | 0 | return false; |
944 | | |
945 | | //Get the encoded corner values. |
946 | 0 | const std::string value = getContents(*pNode); |
947 | | |
948 | | //Decode the extents |
949 | 0 | (void)sscanf(value.c_str(), "%lf,%lf %lf,%lf", |
950 | 0 | &spatialRepresentationInfo.llCornerX, |
951 | 0 | &spatialRepresentationInfo.llCornerY, |
952 | 0 | &spatialRepresentationInfo.urCornerX, |
953 | 0 | &spatialRepresentationInfo.urCornerY); |
954 | 0 | } |
955 | | |
956 | | //smXML:MD_Georectified/transformationDimensionDescription |
957 | 0 | spatialRepresentationInfo.transformationDimensionDescription = |
958 | 0 | getContentsAsCharStar(node, |
959 | 0 | "smXML:MD_Georectified/transformationDimensionDescription"); |
960 | | |
961 | | //smXML:MD_Georectified/transformationDimensionMapping |
962 | 0 | spatialRepresentationInfo.transformationDimensionMapping = |
963 | 0 | getContentsAsCharStar(node, |
964 | 0 | "smXML:MD_Georectified/transformationDimensionMapping"); |
965 | |
|
966 | 0 | } |
967 | 284 | else if (schemaVersion == 2) |
968 | 284 | { |
969 | | //gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionSize |
970 | 284 | spatialRepresentationInfo.numberOfRows = getContentsAsInt(node, |
971 | 284 | "gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionName/gmd:MD_DimensionNameTypeCode[@codeListValue='row']/parent::*/parent::*/gmd:dimensionSize/gco:Integer"); |
972 | | |
973 | | //gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:resolution |
974 | 284 | spatialRepresentationInfo.rowResolution = getContentsAsFloat(node, |
975 | 284 | "gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionName/gmd:MD_DimensionNameTypeCode[@codeListValue='row']/parent::*/parent::*/gmd:resolution/gco:Measure"); |
976 | | |
977 | | //gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionSize |
978 | 284 | spatialRepresentationInfo.numberOfColumns = getContentsAsInt(node, |
979 | 284 | "gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionName/gmd:MD_DimensionNameTypeCode[@codeListValue='column']/parent::*/parent::*/gmd:dimensionSize/gco:Integer"); |
980 | | |
981 | | //gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:resolution |
982 | 284 | spatialRepresentationInfo.columnResolution = getContentsAsFloat(node, |
983 | 284 | "gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionName/gmd:MD_DimensionNameTypeCode[@codeListValue='column']/parent::*/parent::*/gmd:resolution/gco:Measure"); |
984 | | |
985 | | //gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:resolution[@uom] |
986 | 284 | spatialRepresentationInfo.resolutionUnit = getPropertyAsString(node, |
987 | 284 | "gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionName/gmd:MD_DimensionNameTypeCode[@codeListValue='column']/parent::*/parent::*/gmd:resolution/gco:Measure", "uom"); |
988 | | |
989 | | //gmd:MD_Georectified/gmd:cellGeometry |
990 | 284 | delete[] spatialRepresentationInfo.cellGeometry; |
991 | 284 | spatialRepresentationInfo.cellGeometry = getContentsAsCharStar(node, |
992 | 284 | "gmd:MD_Georectified/gmd:cellGeometry/gmd:MD_CellGeometryCode"); |
993 | | |
994 | | //gmd:MD_Georectified/gmd:transformationParameterAvailability |
995 | 284 | spatialRepresentationInfo.transformationParameterAvailability = |
996 | 284 | getContentsAsBool(node, "gmd:MD_Georectified/gmd:transformationParameterAvailability/gco:Boolean"); |
997 | | |
998 | | //gmd:MD_Georectified/gmd:checkPointAvailability |
999 | 284 | spatialRepresentationInfo.checkPointAvailability = getContentsAsBool( |
1000 | 284 | node, "gmd:MD_Georectified/gmd:checkPointAvailability/gco:Boolean"); |
1001 | | |
1002 | | //gmd:MD_Georectified/gmd:cornerPoints/gml:Point |
1003 | 284 | { |
1004 | 284 | const xmlNode *pNode = findNode(node, |
1005 | 284 | "gmd:MD_Georectified/gmd:cornerPoints/gml:Point/gml:coordinates"); |
1006 | 284 | if (!pNode) |
1007 | 0 | return false; |
1008 | | |
1009 | | //Get the encoded corner values. |
1010 | 284 | const std::string value = getContents(*pNode); |
1011 | | |
1012 | | //Decode the extents |
1013 | 284 | (void)sscanf(value.c_str(), "%lf,%lf %lf,%lf", |
1014 | 284 | &spatialRepresentationInfo.llCornerX, |
1015 | 284 | &spatialRepresentationInfo.llCornerY, |
1016 | 284 | &spatialRepresentationInfo.urCornerX, |
1017 | 284 | &spatialRepresentationInfo.urCornerY); |
1018 | 284 | } |
1019 | 284 | } |
1020 | | |
1021 | 284 | return true; |
1022 | 284 | } |
1023 | | |
1024 | | //************************************************************************ |
1025 | | //! Decode a BagIdentification from the supplied XML node. |
1026 | | /*! |
1027 | | \param node |
1028 | | \li The XML node containing the data identification information. |
1029 | | \param dataIdentificationInfo |
1030 | | \li Modified to contain the data identification information from \e node. |
1031 | | \param schemaVersion |
1032 | | \li The version of the schema stored in \e node. |
1033 | | \return |
1034 | | \li True if the information was found and decoded properly, False if |
1035 | | an error occurs. |
1036 | | */ |
1037 | | //************************************************************************ |
1038 | | bool decodeDataIdentificationInfo( |
1039 | | xmlNode& node, |
1040 | | BagIdentification& dataIdentificationInfo, |
1041 | | uint16_t schemaVersion) |
1042 | 284 | { |
1043 | 284 | if (schemaVersion == 1) |
1044 | 0 | { |
1045 | | //smXML:BAG_DataIdentification/citation/smXML:CI_Citation/title |
1046 | 0 | dataIdentificationInfo.title = getContentsAsCharStar(node, |
1047 | 0 | "smXML:BAG_DataIdentification/citation/smXML:CI_Citation/title"); |
1048 | | |
1049 | | //smXML:BAG_DataIdentification/citation/smXML:CI_Citation/date/smXML:CI_Date/date |
1050 | 0 | dataIdentificationInfo.date = getContentsAsCharStar(node, |
1051 | 0 | "smXML:BAG_DataIdentification/citation/smXML:CI_Citation/date/smXML:CI_Date/date"); |
1052 | | |
1053 | | //smXML:BAG_DataIdentification/citation/smXML:CI_Citation/date/smXML:CI_Date/dateType |
1054 | 0 | dataIdentificationInfo.dateType = getContentsAsCharStar(node, |
1055 | 0 | "smXML:BAG_DataIdentification/citation/smXML:CI_Citation/date/smXML:CI_Date/dateType"); |
1056 | | |
1057 | | //smXML:BAG_DataIdentification/citation/smXML:CI_Citation/citedResponsibleParty" |
1058 | 0 | const auto partyNodes = findNodes(node, |
1059 | 0 | "smXML:BAG_DataIdentification/citation/smXML:CI_Citation/citedResponsibleParty"); |
1060 | 0 | if (!partyNodes.empty()) |
1061 | 0 | { |
1062 | 0 | dataIdentificationInfo.numberOfResponsibleParties = |
1063 | 0 | static_cast<uint32_t>(partyNodes.size()); |
1064 | 0 | dataIdentificationInfo.responsibleParties = |
1065 | 0 | new BagResponsibleParty[dataIdentificationInfo.numberOfResponsibleParties]; |
1066 | |
|
1067 | 0 | for (uint32_t i = 0; i < dataIdentificationInfo.numberOfResponsibleParties; i++) |
1068 | 0 | { |
1069 | 0 | initResponsibleParty(dataIdentificationInfo.responsibleParties[i]); |
1070 | 0 | if (!decodeResponsibleParty(*partyNodes[i], |
1071 | 0 | dataIdentificationInfo.responsibleParties[i], schemaVersion)) |
1072 | 0 | return false; |
1073 | 0 | } |
1074 | 0 | } |
1075 | | |
1076 | | //smXML:BAG_DataIdentification/abstract |
1077 | 0 | dataIdentificationInfo.abstractString = getContentsAsCharStar(node, |
1078 | 0 | "smXML:BAG_DataIdentification/abstract"); |
1079 | | |
1080 | | //smXML:BAG_DataIdentification/status |
1081 | 0 | dataIdentificationInfo.status = getContentsAsCharStar(node, |
1082 | 0 | "smXML:BAG_DataIdentification/status"); |
1083 | | |
1084 | | //smXML:BAG_DataIdentification/spatialRepresentationType |
1085 | 0 | dataIdentificationInfo.spatialRepresentationType = getContentsAsCharStar( |
1086 | 0 | node, "smXML:BAG_DataIdentification/spatialRepresentationType"); |
1087 | | |
1088 | | //smXML:BAG_DataIdentification/language |
1089 | 0 | dataIdentificationInfo.language = getContentsAsCharStar(node, |
1090 | 0 | "smXML:BAG_DataIdentification/language"); |
1091 | | |
1092 | | //Doesn't appear to be set, so always set to utf8 |
1093 | 0 | dataIdentificationInfo.characterSet = copyString("utf8"); |
1094 | | |
1095 | | //smXML:BAG_DataIdentification/topicCategory |
1096 | 0 | dataIdentificationInfo.topicCategory = getContentsAsCharStar(node, |
1097 | 0 | "smXML:BAG_DataIdentification/topicCategory"); |
1098 | | |
1099 | | //smXML:BAG_DataIdentification/extent/smXML:EX_Extent/geographicElement/smXML:EX_GeographicBoundingBox/ |
1100 | 0 | dataIdentificationInfo.westBoundingLongitude = getContentsAsFloat(node, |
1101 | 0 | "smXML:BAG_DataIdentification/extent/smXML:EX_Extent/geographicElement/smXML:EX_GeographicBoundingBox/westBoundLongitude"); |
1102 | 0 | dataIdentificationInfo.eastBoundingLongitude = getContentsAsFloat(node, |
1103 | 0 | "smXML:BAG_DataIdentification/extent/smXML:EX_Extent/geographicElement/smXML:EX_GeographicBoundingBox/eastBoundLongitude"); |
1104 | 0 | dataIdentificationInfo.southBoundingLatitude = getContentsAsFloat(node, |
1105 | 0 | "smXML:BAG_DataIdentification/extent/smXML:EX_Extent/geographicElement/smXML:EX_GeographicBoundingBox/southBoundLatitude"); |
1106 | 0 | dataIdentificationInfo.northBoundingLatitude = getContentsAsFloat(node, |
1107 | 0 | "smXML:BAG_DataIdentification/extent/smXML:EX_Extent/geographicElement/smXML:EX_GeographicBoundingBox/northBoundLatitude"); |
1108 | | |
1109 | | //smXML:BAG_DataIdentification/verticalUncertaintyType |
1110 | 0 | dataIdentificationInfo.verticalUncertaintyType = getContentsAsCharStar( |
1111 | 0 | node, "smXML:BAG_DataIdentification/verticalUncertaintyType"); |
1112 | | |
1113 | | //smXML:BAG_DataIdentification/depthCorrectionType |
1114 | 0 | dataIdentificationInfo.depthCorrectionType = getContentsAsCharStar(node, |
1115 | 0 | "smXML:BAG_DataIdentification/depthCorrectionType"); |
1116 | | |
1117 | | //smXML:BAG_DataIdentification/nodeGroupType |
1118 | 0 | dataIdentificationInfo.nodeGroupType = getContentsAsCharStar(node, |
1119 | 0 | "smXML:BAG_DataIdentification/nodeGroupType"); |
1120 | | |
1121 | | //smXML:BAG_DataIdentification/elevationSolutionGroupType |
1122 | 0 | dataIdentificationInfo.elevationSolutionGroupType = getContentsAsCharStar( |
1123 | 0 | node, "smXML:BAG_DataIdentification/elevationSolutionGroupType"); |
1124 | 0 | } |
1125 | 284 | else if (schemaVersion == 2) |
1126 | 284 | { |
1127 | | //bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:title |
1128 | 284 | dataIdentificationInfo.title = getContentsAsCharStar(node, |
1129 | 284 | "bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:title/gco:CharacterString"); |
1130 | | |
1131 | | //bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:CI_Date/gmd:date |
1132 | 284 | dataIdentificationInfo.date = getContentsAsCharStar(node, |
1133 | 284 | "bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:date/gmd:CI_Date/gmd:date/gco:Date"); |
1134 | | |
1135 | | //bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:CI_Date/gmd:dateType |
1136 | 284 | dataIdentificationInfo.dateType = getContentsAsCharStar(node, |
1137 | 284 | "bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:date/gmd:CI_Date/gmd:dateType/gmd:CI_DateTypeCode"); |
1138 | | |
1139 | | //bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:citedResponsibleParty |
1140 | 284 | const auto partyNodes = findNodes(node, |
1141 | 284 | "bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:citedResponsibleParty"); |
1142 | 284 | if (!partyNodes.empty()) |
1143 | 150 | { |
1144 | 150 | dataIdentificationInfo.numberOfResponsibleParties = |
1145 | 150 | static_cast<uint32_t>(partyNodes.size()); |
1146 | 150 | dataIdentificationInfo.responsibleParties = |
1147 | 150 | new BagResponsibleParty[dataIdentificationInfo.numberOfResponsibleParties]; |
1148 | | |
1149 | 300 | for (uint32_t i = 0; i < dataIdentificationInfo.numberOfResponsibleParties; i++) |
1150 | 150 | { |
1151 | 150 | initResponsibleParty(dataIdentificationInfo.responsibleParties[i]); |
1152 | 150 | if (!decodeResponsibleParty(*partyNodes[i], |
1153 | 150 | dataIdentificationInfo.responsibleParties[i], schemaVersion)) |
1154 | 0 | return false; |
1155 | 150 | } |
1156 | 150 | } |
1157 | | |
1158 | | //bag:BAG_DataIdentification/gmd:abstract |
1159 | 284 | dataIdentificationInfo.abstractString = getContentsAsCharStar(node, |
1160 | 284 | "bag:BAG_DataIdentification/gmd:abstract/gco:CharacterString"); |
1161 | | |
1162 | | //bag:BAG_DataIdentification/gmd:status |
1163 | 284 | dataIdentificationInfo.status = getContentsAsCharStar(node, |
1164 | 284 | "bag:BAG_DataIdentification/gmd:status/gmd:MD_ProgressCode"); |
1165 | | |
1166 | | //bag:BAG_DataIdentification/gmd:spatialRepresentationType |
1167 | 284 | dataIdentificationInfo.spatialRepresentationType = getContentsAsCharStar( |
1168 | 284 | node, "bag:BAG_DataIdentification/gmd:spatialRepresentationType/gmd:MD_SpatialRepresentationTypeCode"); |
1169 | | |
1170 | | //bag:BAG_DataIdentification/gmd:language |
1171 | 284 | dataIdentificationInfo.language = getContentsAsCharStar(node, |
1172 | 284 | "bag:BAG_DataIdentification/gmd:language/gmd:LanguageCode"); |
1173 | | |
1174 | | //bag:BAG_DataIdentification/gmd:characterSet |
1175 | 284 | dataIdentificationInfo.characterSet = getContentsAsCharStar(node, |
1176 | 284 | "bag:BAG_DataIdentification/gmd:characterSet/gmd:MD_CharacterSetCode"); |
1177 | | |
1178 | | //bag:BAG_DataIdentification/gmd:topicCategory |
1179 | 284 | dataIdentificationInfo.topicCategory = getContentsAsCharStar(node, |
1180 | 284 | "bag:BAG_DataIdentification/gmd:topicCategory/gmd:MD_TopicCategoryCode"); |
1181 | | |
1182 | | //bag:BAG_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox/ |
1183 | 284 | dataIdentificationInfo.westBoundingLongitude = getContentsAsFloat(node, |
1184 | 284 | "bag:BAG_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox/gmd:westBoundLongitude/gco:Decimal"); |
1185 | 284 | dataIdentificationInfo.eastBoundingLongitude = getContentsAsFloat(node, |
1186 | 284 | "bag:BAG_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox/gmd:eastBoundLongitude/gco:Decimal"); |
1187 | 284 | dataIdentificationInfo.southBoundingLatitude = getContentsAsFloat(node, |
1188 | 284 | "bag:BAG_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox/gmd:southBoundLatitude/gco:Decimal"); |
1189 | 284 | dataIdentificationInfo.northBoundingLatitude = getContentsAsFloat(node, |
1190 | 284 | "bag:BAG_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox/gmd:northBoundLatitude/gco:Decimal"); |
1191 | | |
1192 | | //bag:BAG_DataIdentification/bag:verticalUncertaintyType |
1193 | 284 | dataIdentificationInfo.verticalUncertaintyType = getContentsAsCharStar( |
1194 | 284 | node, "bag:BAG_DataIdentification/bag:verticalUncertaintyType/bag:BAG_VertUncertCode"); |
1195 | | |
1196 | | //bag:BAG_DataIdentification/bag:depthCorrectionType |
1197 | 284 | dataIdentificationInfo.depthCorrectionType = getContentsAsCharStar(node, |
1198 | 284 | "bag:BAG_DataIdentification/bag:depthCorrectionType/bag:BAG_DepthCorrectCode"); |
1199 | | |
1200 | | //bag:BAG_DataIdentification/bag:nodeGroupType |
1201 | 284 | dataIdentificationInfo.nodeGroupType = getContentsAsCharStar(node, |
1202 | 284 | "bag:BAG_DataIdentification/bag:nodeGroupType/bag:BAG_OptGroupCode"); |
1203 | | |
1204 | | //bag:BAG_DataIdentification/bag:elevationSolutionGroupType |
1205 | 284 | dataIdentificationInfo.elevationSolutionGroupType = getContentsAsCharStar( |
1206 | 284 | node, "bag:BAG_DataIdentification/bag:elevationSolutionGroupType/bag:BAG_OptGroupCode"); |
1207 | 284 | } |
1208 | | |
1209 | 284 | return true; |
1210 | 284 | } |
1211 | | |
1212 | | //************************************************************************ |
1213 | | //! Decode a BagReferenceSystem from a BagSpatialRepresentation, the narrowly defined as the parsing of an EPSG code |
1214 | | //! from the transformationDimensionDescription tag |
1215 | | /*! |
1216 | | \param spatialRepresentationInfo |
1217 | | \li Spatial representation information input. |
1218 | | \param referenceSystemInfo |
1219 | | \li Modified to contain the reference system information from \e spatialRepresentationInfo->transformationDimensionDescription. |
1220 | | \param schemaVersion |
1221 | | \li The version of the schema stored in \e node. |
1222 | | \return |
1223 | | \li True if the information was found and decoded properly, False if |
1224 | | the optional tag is not present in the header or an error occurs. |
1225 | | */ |
1226 | | //************************************************************************ |
1227 | | bool decodeReferenceSystemInfoFromSpatial( |
1228 | | const BagSpatialRepresentation* spatialRepresentationInfo, |
1229 | | BagReferenceSystem* referenceSystemInfo, |
1230 | | uint16_t /*schemaVersion*/) |
1231 | 0 | { |
1232 | 0 | if ( spatialRepresentationInfo && referenceSystemInfo ) |
1233 | 0 | { |
1234 | | // Is the TransformationDimensionDescription parameter present? |
1235 | 0 | if ( spatialRepresentationInfo->transformationDimensionDescription ) |
1236 | 0 | { |
1237 | | // Find the assignment operator |
1238 | 0 | auto* equal = strchr( |
1239 | 0 | spatialRepresentationInfo->transformationDimensionDescription, '='); |
1240 | 0 | if (equal != nullptr) |
1241 | 0 | { |
1242 | 0 | ++equal; |
1243 | 0 | const auto epsg = atoi(equal); |
1244 | | |
1245 | | // Proceed to create a string containing the EPSG authority |
1246 | | // code, and set the type to "EPSG". |
1247 | 0 | if (epsg > 0 && strncmp( |
1248 | 0 | spatialRepresentationInfo->transformationDimensionDescription, "EPSG", 4) == 0) |
1249 | 0 | { |
1250 | 0 | char buffer[2048]; |
1251 | |
|
1252 | 0 | sprintf(buffer, "%d", epsg); |
1253 | 0 | referenceSystemInfo->definition = copyString(buffer); |
1254 | 0 | referenceSystemInfo->type = copyString("EPSG"); |
1255 | |
|
1256 | 0 | return true; |
1257 | 0 | } |
1258 | 0 | } |
1259 | 0 | } |
1260 | 0 | } |
1261 | | |
1262 | 0 | return false; |
1263 | 0 | } |
1264 | | |
1265 | | |
1266 | | //************************************************************************ |
1267 | | //! Decode a BagReferenceSystem from the supplied XML node. |
1268 | | /*! |
1269 | | \param node |
1270 | | \li The XML node containing the reference system information. |
1271 | | \param referenceSystemInfo |
1272 | | \li Modified to contain the reference system information from \e node. |
1273 | | \param schemaVersion |
1274 | | \li The version of the schema stored in \e node. |
1275 | | \return |
1276 | | \li True if the information was found and decoded properly, False if |
1277 | | an error occurs. |
1278 | | */ |
1279 | | //************************************************************************ |
1280 | | bool decodeReferenceSystemInfo( |
1281 | | xmlNode& node, |
1282 | | BagReferenceSystem& referenceSystemInfo, |
1283 | | uint16_t schemaVersion) |
1284 | 568 | { |
1285 | 568 | if (schemaVersion == 1) |
1286 | 0 | { |
1287 | | //If I have an ellipsoid, then this must be horizontal. |
1288 | 0 | auto ellipsoid = getContentsAsString(node, "smXML:MD_CRS/ellipsoid/smXML:RS_Identifier/code"); |
1289 | 0 | if (!ellipsoid.empty()) |
1290 | 0 | { |
1291 | 0 | auto projectionId = getContentsAsString(node, "smXML:MD_CRS/projection/smXML:RS_Identifier/code"); |
1292 | 0 | auto datumId = getContentsAsString(node, "smXML:MD_CRS/datum/smXML:RS_Identifier/code"); |
1293 | |
|
1294 | 0 | BagLegacyReferenceSystem v1Def; |
1295 | 0 | memset(&v1Def, 0, sizeof(BagLegacyReferenceSystem)); |
1296 | | |
1297 | | //Store the projection information. |
1298 | 0 | v1Def.coordSys = bagCoordsys(projectionId.c_str()); |
1299 | | |
1300 | | //Store the ellipsoid information. |
1301 | 0 | strncpy(v1Def.geoParameters.ellipsoid, ellipsoid.c_str(), 256); |
1302 | | |
1303 | | //Store the datum information. |
1304 | 0 | v1Def.geoParameters.datum = bagDatumID(datumId.c_str()); |
1305 | |
|
1306 | 0 | v1Def.geoParameters.zone = getContentsAsInt(node, |
1307 | 0 | "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/zone"); |
1308 | 0 | v1Def.geoParameters.std_parallel_1 = getContentsAsFloat(node, |
1309 | 0 | "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/standardParallel[1]"); |
1310 | 0 | v1Def.geoParameters.std_parallel_2 = getContentsAsFloat(node, |
1311 | 0 | "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/standardParallel[2]"); |
1312 | 0 | v1Def.geoParameters.central_meridian = getContentsAsFloat(node, |
1313 | 0 | "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/longitudeOfCentralMeridian"); |
1314 | 0 | v1Def.geoParameters.origin_latitude = getContentsAsFloat(node, |
1315 | 0 | "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/latitudeOfProjectionOrigin"); |
1316 | 0 | v1Def.geoParameters.false_easting = getContentsAsFloat(node, |
1317 | 0 | "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/falseEasting"); |
1318 | 0 | v1Def.geoParameters.false_northing = getContentsAsFloat(node, |
1319 | 0 | "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/falseNorthing"); |
1320 | 0 | const double scaleFactAtEq = getContentsAsFloat(node, |
1321 | 0 | "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/scaleFactorAtEquator"); |
1322 | 0 | v1Def.geoParameters.longitude_of_centre = getContentsAsFloat(node, |
1323 | 0 | "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/longitudeOfProjectionCenter"); |
1324 | 0 | v1Def.geoParameters.latitude_of_centre = getContentsAsFloat(node, |
1325 | 0 | "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/latitudeOfProjectionCenter"); |
1326 | 0 | v1Def.geoParameters.longitude_down_from_pole = getContentsAsFloat( |
1327 | 0 | node, "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/straightVerticalLongitudeFromPole"); |
1328 | 0 | const double scaleAtProjOrigin = getContentsAsFloat(node, |
1329 | 0 | "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/scaleFactorAtProjectionOrigin"); |
1330 | | |
1331 | | /* dhf */ |
1332 | | /* scaleFactAtEq - for mercator */ |
1333 | | /* scaleAtCenterLine - for oblique mercator (not supported) */ |
1334 | | /* scaleAtProjOrigin - for polar stereographic & transverse mercator */ |
1335 | 0 | if (v1Def.coordSys == CoordinateType::Mercator) |
1336 | 0 | v1Def.geoParameters.scale_factor = scaleFactAtEq; |
1337 | 0 | if (v1Def.coordSys == CoordinateType::Transverse_Mercator || |
1338 | 0 | v1Def.coordSys == CoordinateType::Polar_Stereo) |
1339 | 0 | v1Def.geoParameters.scale_factor = scaleAtProjOrigin; |
1340 | |
|
1341 | 0 | char buffer[2048]; |
1342 | 0 | const BagError error = bagLegacyToWkt(v1Def, buffer, sizeof(buffer), |
1343 | 0 | nullptr, 0); |
1344 | 0 | if (error) |
1345 | 0 | return false; |
1346 | | |
1347 | 0 | referenceSystemInfo.definition = copyString(buffer); |
1348 | 0 | referenceSystemInfo.type = copyString("WKT"); |
1349 | 0 | } |
1350 | | //Else it must be vertical. |
1351 | 0 | else |
1352 | 0 | { |
1353 | 0 | auto datum = getContentsAsString(node, "smXML:MD_CRS/datum/smXML:RS_Identifier/code"); |
1354 | |
|
1355 | 0 | BagLegacyReferenceSystem system; |
1356 | 0 | strncpy(system.geoParameters.vertical_datum, datum.c_str(), 256); |
1357 | |
|
1358 | 0 | char buffer[1024]; |
1359 | 0 | const BagError error = bagLegacyToWkt(system, nullptr, 0, buffer, |
1360 | 0 | sizeof(buffer)); |
1361 | 0 | if (error) |
1362 | 0 | return false; |
1363 | | |
1364 | 0 | referenceSystemInfo.definition = copyString(buffer); |
1365 | 0 | referenceSystemInfo.type = copyString("WKT"); |
1366 | 0 | } |
1367 | 0 | } |
1368 | 568 | else if (schemaVersion == 2) |
1369 | 568 | { |
1370 | | //gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:code |
1371 | 568 | referenceSystemInfo.definition = getContentsAsCharStar(node, |
1372 | 568 | "gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:code/gco:CharacterString"); |
1373 | | |
1374 | | //gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:codeSpace |
1375 | 568 | referenceSystemInfo.type = getContentsAsCharStar(node, |
1376 | 568 | "gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:codeSpace/gco:CharacterString"); |
1377 | 568 | } |
1378 | | |
1379 | 568 | return true; |
1380 | 568 | } |
1381 | | |
1382 | | //************************************************************************ |
1383 | | //! Validate an XML document against the current BAG metadata schema. |
1384 | | /*! |
1385 | | \param metadataDocument |
1386 | | \li The document to be validated. |
1387 | | \return |
1388 | | \li BAG_SUCCESS if the document passes schema validation, a BAG error |
1389 | | code if an error occurs. |
1390 | | */ |
1391 | | //************************************************************************ |
1392 | | BagError validateSchema(xmlDoc& metadataDocument) |
1393 | 0 | { |
1394 | | //Get the location of the BAG home directory. |
1395 | 0 | const std::string bagHome = bagGetHomeFolder(); |
1396 | |
|
1397 | 0 | if (bagHome.empty()) |
1398 | 0 | return BAG_METADTA_NO_HOME; |
1399 | | |
1400 | | //Build the full path to the schema location. |
1401 | 0 | std::string schemaFile(bagHome); |
1402 | 0 | schemaFile += "/"; |
1403 | 0 | schemaFile += ons_schema_location; |
1404 | | |
1405 | | // make sure the main schema file exists. |
1406 | 0 | struct stat fStat; |
1407 | 0 | if (stat(schemaFile.c_str(), &fStat)) |
1408 | 0 | return BAG_METADTA_SCHEMA_FILE_MISSING; |
1409 | | |
1410 | | // Open the schema. |
1411 | 0 | xmlDoc *pSchemaDoc = xmlParseFile(schemaFile.c_str()); |
1412 | 0 | if (!pSchemaDoc) |
1413 | 0 | return BAG_METADTA_PARSE_FAILED; |
1414 | | |
1415 | | // Parse the schema. |
1416 | 0 | xmlSchemaParserCtxt *pContext = xmlSchemaNewDocParserCtxt(pSchemaDoc); |
1417 | 0 | if (!pContext) |
1418 | 0 | { |
1419 | 0 | xmlFreeDoc(pSchemaDoc); |
1420 | |
|
1421 | 0 | return BAG_METADTA_SCHEMA_SETUP_FAILED; |
1422 | 0 | } |
1423 | | |
1424 | | // Initialize the schema object. |
1425 | 0 | xmlSchema *pSchema = xmlSchemaParse(pContext); |
1426 | 0 | if (!pSchema) |
1427 | 0 | { |
1428 | 0 | xmlSchemaFreeParserCtxt(pContext); |
1429 | 0 | xmlFreeDoc(pSchemaDoc); |
1430 | |
|
1431 | 0 | return BAG_METADTA_SCHEMA_SETUP_FAILED; |
1432 | 0 | } |
1433 | | |
1434 | | // Create the validation object. |
1435 | 0 | xmlSchemaValidCtxt *pValidationContext = xmlSchemaNewValidCtxt(pSchema); |
1436 | 0 | if (!pValidationContext) |
1437 | 0 | { |
1438 | 0 | xmlSchemaFree(pSchema); |
1439 | 0 | xmlSchemaFreeParserCtxt(pContext); |
1440 | 0 | xmlFreeDoc(pSchemaDoc); |
1441 | |
|
1442 | 0 | return BAG_METADTA_SCHEMA_VALIDATION_SETUP_FAILED; |
1443 | 0 | } |
1444 | | |
1445 | | // Validate the document. |
1446 | 0 | const int result = xmlSchemaValidateDoc(pValidationContext, &metadataDocument); |
1447 | |
|
1448 | 0 | xmlSchemaFreeValidCtxt(pValidationContext); |
1449 | 0 | xmlSchemaFree(pSchema); |
1450 | 0 | xmlSchemaFreeParserCtxt(pContext); |
1451 | 0 | xmlFreeDoc(pSchemaDoc); |
1452 | |
|
1453 | 0 | return (result == 0) ? BAG_SUCCESS : BAG_METADTA_VALIDATE_FAILED; |
1454 | 0 | } |
1455 | | |
1456 | | //************************************************************************ |
1457 | | //! Import the BAG_METADATA from a version 1 schema. |
1458 | | /*! |
1459 | | Imports the metadata from a 'version 1' BAG schema. Version 1 schemas |
1460 | | were used in BAG versions 1.0 - 1.4. Version 2 schemas are used in |
1461 | | BAG version 1.5 and newer. |
1462 | | |
1463 | | \param document |
1464 | | \li The XML document containing the 'version 1' schema. |
1465 | | \param metadata |
1466 | | \li Modified to contain the BAG metadata information from \e document. |
1467 | | Input should not be NULL. |
1468 | | \return |
1469 | | \li BAG_SUCCESS if the information is successfully extracted from \e document, |
1470 | | an error code otherwise. |
1471 | | */ |
1472 | | //************************************************************************ |
1473 | | BagError bagImportMetadataFromXmlV1( |
1474 | | const xmlDoc& document, |
1475 | | BagMetadata& metadata) |
1476 | 0 | { |
1477 | 0 | xmlNode* pRoot = xmlDocGetRootElement(&document); |
1478 | 0 | if (!pRoot) |
1479 | 0 | return BAG_METADTA_NOT_INITIALIZED; |
1480 | | |
1481 | | //gmd:language |
1482 | 0 | metadata.language = getContentsAsCharStar(*pRoot, "/smXML:MD_Metadata/language"); |
1483 | | |
1484 | | //gmd:characterSet |
1485 | 0 | metadata.characterSet = copyString("eng"); |
1486 | | |
1487 | | //gmd:hierarchyLevel |
1488 | 0 | metadata.hierarchyLevel = copyString("dataset"); |
1489 | | |
1490 | | //gmd:contact |
1491 | 0 | { |
1492 | 0 | auto* pNode = findNode(*pRoot, "/smXML:MD_Metadata/contact"); |
1493 | 0 | if (!pNode) |
1494 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1495 | | |
1496 | 0 | if (!decodeResponsibleParty(*pNode, *metadata.contact, 1)) |
1497 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1498 | 0 | } |
1499 | | |
1500 | | //gmd:dateStamp |
1501 | 0 | metadata.dateStamp = getContentsAsCharStar(*pRoot, |
1502 | 0 | "/smXML:MD_Metadata/dateStamp"); |
1503 | | |
1504 | | //gmd:metadataStandardName |
1505 | 0 | metadata.metadataStandardName = getContentsAsCharStar(*pRoot, |
1506 | 0 | "/smXML:MD_Metadata/metadataStandardName"); |
1507 | | |
1508 | | //gmd:metadataStandardVersion |
1509 | 0 | metadata.metadataStandardVersion = getContentsAsCharStar(*pRoot, |
1510 | 0 | "/smXML:MD_Metadata/metadataStandardVersion"); |
1511 | | |
1512 | | //gmd:spatialRepresentationInfo |
1513 | 0 | { |
1514 | 0 | auto* pNode = findNode(*pRoot, |
1515 | 0 | "/smXML:MD_Metadata/spatialRepresentationInfo"); |
1516 | 0 | if (!pNode) |
1517 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1518 | | |
1519 | 0 | if (!decodeSpatialRepresentationInfo(*pNode, |
1520 | 0 | *metadata.spatialRepresentationInfo, 1)) |
1521 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1522 | 0 | } |
1523 | | |
1524 | | //gmd:referenceSystemInfo (horizontal) |
1525 | 0 | { |
1526 | 0 | auto* pNode = findNode(*pRoot, |
1527 | 0 | "/smXML:MD_Metadata/referenceSystemInfo[1]"); |
1528 | 0 | if (!pNode) |
1529 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1530 | | |
1531 | 0 | if (!decodeReferenceSystemInfo(*pNode, *metadata.horizontalReferenceSystem, 1)) |
1532 | 0 | { |
1533 | | // If the reference system could not be identified from this block |
1534 | | // of code look for an EPSG code in the spatial reference system |
1535 | 0 | if (!decodeReferenceSystemInfoFromSpatial( |
1536 | 0 | metadata.spatialRepresentationInfo, |
1537 | 0 | metadata.horizontalReferenceSystem, 1)) |
1538 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1539 | 0 | } |
1540 | 0 | } |
1541 | | |
1542 | | //gmd:referenceSystemInfo (vertical) |
1543 | 0 | { |
1544 | 0 | auto* pNode = findNode(*pRoot, |
1545 | 0 | "/smXML:MD_Metadata/referenceSystemInfo[2]"); |
1546 | 0 | if (!pNode) |
1547 | 0 | { |
1548 | | //If we could not find the vertical coordinate system node, then |
1549 | | //lets look in the other location. |
1550 | 0 | auto* pNode2 = findNode(*pRoot, |
1551 | 0 | "/smXML:MD_Metadata/referenceSystemInfo[1]//verticalDatum"); |
1552 | 0 | if (!pNode2) |
1553 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1554 | | |
1555 | 0 | const auto datum = getContentsAsString(*pNode2, |
1556 | 0 | "smXML:RS_Identifier/code"); |
1557 | 0 | if (datum.empty()) |
1558 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1559 | | |
1560 | 0 | BagLegacyReferenceSystem system; |
1561 | 0 | strncpy(system.geoParameters.vertical_datum, datum.c_str(), 256); |
1562 | |
|
1563 | 0 | char buffer[1024]; |
1564 | 0 | BagError error = bagLegacyToWkt(system, nullptr, 0, buffer, |
1565 | 0 | sizeof(buffer)); |
1566 | 0 | if (error) |
1567 | 0 | return error; |
1568 | | |
1569 | 0 | metadata.verticalReferenceSystem->definition = copyString(buffer); |
1570 | 0 | metadata.verticalReferenceSystem->type = copyString("WKT"); |
1571 | 0 | } |
1572 | 0 | else if (!decodeReferenceSystemInfo(*pNode, |
1573 | 0 | *metadata.verticalReferenceSystem, 1)) |
1574 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1575 | 0 | } |
1576 | | |
1577 | | //Because the previous metadata profile did not store the unit of measure |
1578 | | //for the spatial representation element, we will use the spatial reference |
1579 | | //system to figure it out. |
1580 | 0 | { |
1581 | | //Get the WKT horizontal reference system string. |
1582 | 0 | const std::string horizontalWKT{ |
1583 | 0 | metadata.horizontalReferenceSystem->definition}; |
1584 | | |
1585 | | //If we have a projection, then it must be metres (its all we supported in the past) |
1586 | 0 | if (horizontalWKT.find("PROJCS[") >= 0) |
1587 | 0 | metadata.spatialRepresentationInfo->resolutionUnit = copyString("Metre"); |
1588 | | //Else it must be geographic |
1589 | 0 | else |
1590 | 0 | metadata.spatialRepresentationInfo->resolutionUnit = copyString("Degree"); |
1591 | 0 | } |
1592 | | |
1593 | | //gmd:identificationInfo |
1594 | 0 | { |
1595 | 0 | auto* pNode = findNode(*pRoot, "/smXML:MD_Metadata/identificationInfo"); |
1596 | 0 | if (!pNode) |
1597 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1598 | | |
1599 | 0 | if (!decodeDataIdentificationInfo(*pNode, *metadata.identificationInfo, 1)) |
1600 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1601 | 0 | } |
1602 | | |
1603 | | //gmd:dataQualityInfo |
1604 | 0 | { |
1605 | 0 | auto* pNode = findNode(*pRoot, "/smXML:MD_Metadata/dataQualityInfo"); |
1606 | 0 | if (!pNode) |
1607 | 0 | { |
1608 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1609 | 0 | } |
1610 | | |
1611 | 0 | if (!decodeDataQualityInfo(*pNode, *metadata.dataQualityInfo, 1)) |
1612 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1613 | 0 | } |
1614 | | |
1615 | | //gmd:metadataConstraints (legal) |
1616 | 0 | { |
1617 | 0 | auto* pNode = findNode(*pRoot, |
1618 | 0 | "/smXML:MD_Metadata/metadataConstraints/smXML:MD_LegalConstraints/parent::*"); |
1619 | 0 | if (!pNode) |
1620 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1621 | | |
1622 | 0 | if (!decodeLegalConstraints(*pNode, *metadata.legalConstraints, 1)) |
1623 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1624 | 0 | } |
1625 | | |
1626 | | //gmd:metadataConstraints (security) |
1627 | 0 | { |
1628 | 0 | auto* pNode = findNode(*pRoot, |
1629 | 0 | "/smXML:MD_Metadata/metadataConstraints/smXML:MD_SecurityConstraints/parent::*"); |
1630 | 0 | if (!pNode) |
1631 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1632 | | |
1633 | 0 | if (!decodeSecurityConstraints(*pNode, *metadata.securityConstraints, 1)) |
1634 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1635 | 0 | } |
1636 | | |
1637 | 0 | return BAG_SUCCESS; |
1638 | 0 | } |
1639 | | |
1640 | | //************************************************************************ |
1641 | | //! Import the BAG_METADATA from a version 2 schema. |
1642 | | /*! |
1643 | | Imports the metadata from a 'version 2' BAG schema. Version 2 schemas |
1644 | | are used in BAG version 1.5 and newer. |
1645 | | |
1646 | | \param document |
1647 | | \li The XML document containing the 'version 2' schema. |
1648 | | \param metadata |
1649 | | \li Modified to contain the BAG metadata information from \e document. |
1650 | | Input should not be NULL. |
1651 | | \return |
1652 | | \li BAG_SUCCESS if the information is successfully extracted from \e document, |
1653 | | an error code otherwise. |
1654 | | */ |
1655 | | //************************************************************************ |
1656 | | BagError bagImportMetadataFromXmlV2( |
1657 | | const xmlDoc& document, |
1658 | | BagMetadata& metadata) |
1659 | 284 | { |
1660 | 284 | auto* pRoot = xmlDocGetRootElement(&document); |
1661 | 284 | if (!pRoot) |
1662 | 0 | return BAG_METADTA_NOT_INITIALIZED; |
1663 | | |
1664 | | //gmd:fileIdentifier |
1665 | 284 | delete[] metadata.fileIdentifier; |
1666 | 284 | metadata.fileIdentifier = getContentsAsCharStar(*pRoot, |
1667 | 284 | "/gmi:MI_Metadata/gmd:fileIdentifier/gco:CharacterString"); |
1668 | | |
1669 | | //gmd:language |
1670 | 284 | delete[] metadata.language; |
1671 | 284 | metadata.language = getContentsAsCharStar(*pRoot, |
1672 | 284 | "/gmi:MI_Metadata/gmd:language/gmd:LanguageCode"); |
1673 | | |
1674 | | //gmd:characterSet |
1675 | 284 | delete[] metadata.characterSet; |
1676 | 284 | metadata.characterSet = getContentsAsCharStar(*pRoot, |
1677 | 284 | "/gmi:MI_Metadata/gmd:characterSet/gmd:MD_CharacterSetCode"); |
1678 | | |
1679 | | //gmd:hierarchyLevel |
1680 | 284 | delete[] metadata.hierarchyLevel; |
1681 | 284 | metadata.hierarchyLevel = getContentsAsCharStar(*pRoot, |
1682 | 284 | "/gmi:MI_Metadata/gmd:hierarchyLevel/gmd:MD_ScopeCode"); |
1683 | | |
1684 | | //gmd:contact |
1685 | 284 | { |
1686 | 284 | auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:contact"); |
1687 | 284 | if (!pNode) |
1688 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1689 | | |
1690 | 284 | if (!decodeResponsibleParty(*pNode, *metadata.contact, 2)) |
1691 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1692 | 284 | } |
1693 | | |
1694 | | //gmd:dateStamp |
1695 | 284 | delete[] metadata.dateStamp; |
1696 | 284 | metadata.dateStamp = getContentsAsCharStar(*pRoot, |
1697 | 284 | "/gmi:MI_Metadata/gmd:dateStamp/gco:Date"); |
1698 | | |
1699 | | //gmd:metadataStandardName |
1700 | 284 | delete[] metadata.metadataStandardName; |
1701 | 284 | metadata.metadataStandardName = getContentsAsCharStar(*pRoot, |
1702 | 284 | "/gmi:MI_Metadata/gmd:metadataStandardName/gco:CharacterString"); |
1703 | | |
1704 | | //gmd:metadataStandardVersion |
1705 | 284 | delete[] metadata.metadataStandardVersion; |
1706 | 284 | metadata.metadataStandardVersion = getContentsAsCharStar(*pRoot, |
1707 | 284 | "/gmi:MI_Metadata/gmd:metadataStandardVersion/gco:CharacterString"); |
1708 | | |
1709 | | //gmd:spatialRepresentationInfo |
1710 | 284 | { |
1711 | 284 | auto* pNode = findNode(*pRoot, |
1712 | 284 | "/gmi:MI_Metadata/gmd:spatialRepresentationInfo/gmd:MD_Georectified/parent::*"); |
1713 | 284 | if (!pNode) |
1714 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1715 | | |
1716 | 284 | if (!decodeSpatialRepresentationInfo(*pNode, *metadata.spatialRepresentationInfo, 2)) |
1717 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1718 | 284 | } |
1719 | | |
1720 | | //gmd:referenceSystemInfo (horizontal) |
1721 | 284 | { |
1722 | 284 | auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:referenceSystemInfo[1]"); |
1723 | 284 | if (!pNode) |
1724 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1725 | | |
1726 | 284 | if (!decodeReferenceSystemInfo(*pNode, *metadata.horizontalReferenceSystem, 2)) |
1727 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1728 | 284 | } |
1729 | | |
1730 | | //gmd:referenceSystemInfo (vertical) |
1731 | 284 | { |
1732 | 284 | auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:referenceSystemInfo[2]"); |
1733 | 284 | if (!pNode) |
1734 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1735 | | |
1736 | 284 | if (!decodeReferenceSystemInfo(*pNode, *metadata.verticalReferenceSystem, 2)) |
1737 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1738 | 284 | } |
1739 | | |
1740 | | //gmd:identificationInfo |
1741 | 284 | { |
1742 | 284 | auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:identificationInfo"); |
1743 | 284 | if (!pNode) |
1744 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1745 | | |
1746 | 284 | if (!decodeDataIdentificationInfo(*pNode, *metadata.identificationInfo, 2)) |
1747 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1748 | 284 | } |
1749 | | |
1750 | | //gmd:dataQualityInfo |
1751 | 284 | { |
1752 | 284 | auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:dataQualityInfo"); |
1753 | 284 | if (!pNode) |
1754 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1755 | | |
1756 | 284 | if (!decodeDataQualityInfo(*pNode, *metadata.dataQualityInfo, 2)) |
1757 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1758 | 284 | } |
1759 | | |
1760 | | //gmd:metadataConstraints (legal) |
1761 | 284 | { |
1762 | 284 | auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:metadataConstraints/gmd:MD_LegalConstraints/parent::*"); |
1763 | 284 | if (!pNode) |
1764 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1765 | | |
1766 | 284 | if (!decodeLegalConstraints(*pNode, *metadata.legalConstraints, 2)) |
1767 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1768 | 284 | } |
1769 | | |
1770 | | //gmd:metadataConstraints (security) |
1771 | 284 | { |
1772 | 284 | auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:metadataConstraints/gmd:MD_SecurityConstraints/parent::*"); |
1773 | 284 | if (!pNode) |
1774 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1775 | | |
1776 | 284 | if (!decodeSecurityConstraints(*pNode, *metadata.securityConstraints, 2)) |
1777 | 0 | return BAG_METADTA_MISSING_MANDATORY_ITEM; |
1778 | 284 | } |
1779 | | |
1780 | 284 | return BAG_SUCCESS; |
1781 | 284 | } |
1782 | | |
1783 | | //************************************************************************ |
1784 | | //! Import the BAG_METADATA from an XML document. |
1785 | | /*! |
1786 | | Imports the BAG metadata information from any supported schema version. |
1787 | | |
1788 | | \param document |
1789 | | \li The XML document containing the 'version 2' schema. |
1790 | | \param metadata |
1791 | | \li Modified to contain the BAG metadata information from \e document. |
1792 | | Input should not be NULL. |
1793 | | \param doValidation |
1794 | | \li True to perform the schema validation (conformance test). False |
1795 | | to simply extract the data. |
1796 | | \return |
1797 | | \li BAG_SUCCESS on success. A BAG error code is returned if there |
1798 | | is an error, or if schema validation fails (only if \e doValidation |
1799 | | is True). |
1800 | | */ |
1801 | | //************************************************************************ |
1802 | | BagError bagImportMetadataFromXml( |
1803 | | xmlDoc& document, |
1804 | | BagMetadata& metadata, |
1805 | | bool doValidation) |
1806 | 284 | { |
1807 | 284 | const xmlNode* pRoot = xmlDocGetRootElement(&document); |
1808 | 284 | if (!pRoot) |
1809 | 0 | return BAG_METADTA_EMPTY_DOCUMENT; |
1810 | | |
1811 | 284 | if (doValidation) |
1812 | 0 | { |
1813 | 0 | const BagError ret = validateSchema(document); |
1814 | 0 | if (ret) |
1815 | 0 | return ret; |
1816 | 0 | } |
1817 | | |
1818 | | //Get the name of the root node. |
1819 | 284 | const std::string rootName = getNodeName(*pRoot); |
1820 | | |
1821 | | //We will use the root node's name to figure out what version of the schema we are working with. |
1822 | 284 | const uint16_t schemaVersion = (rootName == "smXML:MD_Metadata") ? 1 : 2; |
1823 | | |
1824 | 284 | return (schemaVersion == 1) ? |
1825 | 0 | bagImportMetadataFromXmlV1(document, metadata) : |
1826 | 284 | bagImportMetadataFromXmlV2(document, metadata); |
1827 | 284 | } |
1828 | | |
1829 | | //************************************************************************ |
1830 | | //! Import the BAG_METADATA from an XML document stored in a character buffer. |
1831 | | /*! |
1832 | | Imports the BAG metadata information from any supported schema version. |
1833 | | |
1834 | | \param xmlBuffer |
1835 | | \li The character buffer containing the XML document to be used for |
1836 | | import. Input should not be NULL. |
1837 | | \param bufferSize |
1838 | | \li The size in bytes of the \e xmlBuffer. |
1839 | | \param metadata |
1840 | | \li Modified to contain the BAG metadata information from \e xmlBuffer. |
1841 | | Input should not be NULL. |
1842 | | \param doValidation |
1843 | | \li True to perform the schema validation (conformance test). False |
1844 | | to simply extract the data. |
1845 | | \return |
1846 | | \li BAG_SUCCESS if the information is successfully extracted from \e xmlBuffer, |
1847 | | an error code otherwise. If \e doValidation is True, an error will be returned |
1848 | | if the validation fails. |
1849 | | */ |
1850 | | //************************************************************************ |
1851 | | BagError bagImportMetadataFromXmlBuffer( |
1852 | | const char* xmlBuffer, |
1853 | | int bufferSize, |
1854 | | BagMetadata& metadata, |
1855 | | bool doValidation) |
1856 | 284 | { |
1857 | 284 | xmlDoc* pDocument = xmlParseMemory(xmlBuffer, bufferSize); |
1858 | 284 | if (!pDocument) |
1859 | 0 | return BAG_METADTA_NOT_INITIALIZED; |
1860 | | |
1861 | 284 | const BagError err = bagImportMetadataFromXml(*pDocument, metadata, doValidation); |
1862 | 284 | xmlFreeDoc(pDocument); |
1863 | 284 | return err; |
1864 | 284 | } |
1865 | | |
1866 | | //************************************************************************ |
1867 | | //! Import the BAG_METADATA from an XML file. |
1868 | | /*! |
1869 | | Imports the BAG metadata information from any supported schema version. |
1870 | | |
1871 | | \param fileName |
1872 | | \li The fully qualified name of the XML file to be read. |
1873 | | \param metadata |
1874 | | \li Modified to contain the BAG metadata information from \e fileName. |
1875 | | Input should not be NULL. |
1876 | | \param doValidation |
1877 | | \li True to perform the schema validation (conformance test). False |
1878 | | to simply extract the data. |
1879 | | \return |
1880 | | \li BAG_SUCCESS if the information is successfully extracted from \e xmlBuffer, |
1881 | | an error code otherwise. If \e doValidation is True, an error will be returned |
1882 | | if the validation fails. |
1883 | | */ |
1884 | | //************************************************************************ |
1885 | | BagError bagImportMetadataFromXmlFile( |
1886 | | const char* fileName, |
1887 | | BagMetadata& metadata, |
1888 | | bool doValidation) |
1889 | 0 | { |
1890 | 0 | xmlDoc* pDocument = xmlParseFile(fileName); |
1891 | 0 | if (!pDocument) |
1892 | 0 | return BAG_METADTA_NOT_INITIALIZED; |
1893 | | |
1894 | 0 | const BagError err = bagImportMetadataFromXml(*pDocument, metadata, doValidation); |
1895 | 0 | xmlFreeDoc(pDocument); |
1896 | 0 | return err; |
1897 | 0 | } |
1898 | | |
1899 | | } // namespace BAG |
1900 | | |