/src/gdal/ogr/ogrsf_frmts/openfilegdb/filegdb_fielddomain.h
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: Implements Open FileGDB OGR driver. |
5 | | * Author: Even Rouault, <even dot rouault at spatialys.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2021, Even Rouault <even dot rouault at spatialys.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #ifndef FILEGDB_FIELDDOMAIN_H |
14 | | #define FILEGDB_FIELDDOMAIN_H |
15 | | |
16 | | #include "cpl_minixml.h" |
17 | | #include "filegdb_gdbtoogrfieldtype.h" |
18 | | #include "ogr_p.h" |
19 | | |
20 | | /************************************************************************/ |
21 | | /* ParseXMLFieldDomainDef() */ |
22 | | /************************************************************************/ |
23 | | |
24 | | inline std::unique_ptr<OGRFieldDomain> |
25 | | ParseXMLFieldDomainDef(const std::string &domainDef) |
26 | 11.6k | { |
27 | 11.6k | CPLXMLTreeCloser oTree(CPLParseXMLString(domainDef.c_str())); |
28 | 11.6k | if (!oTree.get()) |
29 | 7.27k | { |
30 | 7.27k | return nullptr; |
31 | 7.27k | } |
32 | 4.40k | const CPLXMLNode *psDomain = CPLGetXMLNode(oTree.get(), "=esri:Domain"); |
33 | 4.40k | if (psDomain == nullptr) |
34 | 4.20k | { |
35 | | // esri: namespace prefix omitted when called from the FileGDB driver |
36 | 4.20k | psDomain = CPLGetXMLNode(oTree.get(), "=Domain"); |
37 | 4.20k | } |
38 | 4.40k | bool bIsCodedValueDomain = false; |
39 | 4.40k | if (psDomain == nullptr) |
40 | 4.20k | { |
41 | | // Also sometimes found... |
42 | 4.20k | psDomain = CPLGetXMLNode(oTree.get(), "=esri:CodedValueDomain"); |
43 | 4.20k | if (psDomain) |
44 | 212 | bIsCodedValueDomain = true; |
45 | 4.20k | } |
46 | 4.40k | if (psDomain == nullptr) |
47 | 3.98k | { |
48 | | // Also sometimes found... |
49 | 3.98k | psDomain = CPLGetXMLNode(oTree.get(), "=typens:GPCodedValueDomain2"); |
50 | 3.98k | if (psDomain) |
51 | 708 | bIsCodedValueDomain = true; |
52 | 3.98k | } |
53 | 4.40k | if (psDomain == nullptr) |
54 | 3.28k | { |
55 | | // Also sometimes found... |
56 | 3.28k | psDomain = CPLGetXMLNode(oTree.get(), "=GPCodedValueDomain2"); |
57 | 3.28k | if (psDomain) |
58 | 395 | bIsCodedValueDomain = true; |
59 | 3.28k | } |
60 | 4.40k | bool bIsRangeDomain = false; |
61 | 4.40k | if (psDomain == nullptr) |
62 | 2.88k | { |
63 | | // Also sometimes found... |
64 | 2.88k | psDomain = CPLGetXMLNode(oTree.get(), "=esri:RangeDomain"); |
65 | 2.88k | if (psDomain) |
66 | 371 | bIsRangeDomain = true; |
67 | 2.88k | } |
68 | 4.40k | if (psDomain == nullptr) |
69 | 2.51k | { |
70 | | // Also sometimes found... |
71 | 2.51k | psDomain = CPLGetXMLNode(oTree.get(), "=typens:GPRangeDomain2"); |
72 | 2.51k | if (psDomain) |
73 | 426 | bIsRangeDomain = true; |
74 | 2.51k | } |
75 | 4.40k | if (psDomain == nullptr) |
76 | 2.08k | { |
77 | | // Also sometimes found... |
78 | 2.08k | psDomain = CPLGetXMLNode(oTree.get(), "=GPRangeDomain2"); |
79 | 2.08k | if (psDomain) |
80 | 194 | bIsRangeDomain = true; |
81 | 2.08k | } |
82 | 4.40k | if (psDomain == nullptr) |
83 | 1.89k | { |
84 | 1.89k | CPLError(CE_Failure, CPLE_AppDefined, "Cannot find root 'Domain' node"); |
85 | 1.89k | return nullptr; |
86 | 1.89k | } |
87 | 2.50k | const char *pszType = CPLGetXMLValue(psDomain, "xsi:type", ""); |
88 | 2.50k | const char *pszName = CPLGetXMLValue(psDomain, "DomainName", ""); |
89 | 2.50k | const char *pszDescription = CPLGetXMLValue(psDomain, "Description", ""); |
90 | 2.50k | const char *pszFieldType = CPLGetXMLValue(psDomain, "FieldType", ""); |
91 | 2.50k | OGRFieldType eFieldType = OFTString; |
92 | 2.50k | OGRFieldSubType eSubType = OFSTNone; |
93 | 2.50k | if (!GDBToOGRFieldType(pszFieldType, &eFieldType, &eSubType)) |
94 | 2.50k | { |
95 | 2.50k | return nullptr; |
96 | 2.50k | } |
97 | | |
98 | 0 | std::unique_ptr<OGRFieldDomain> domain; |
99 | 0 | if (bIsCodedValueDomain || strcmp(pszType, "esri:CodedValueDomain") == 0) |
100 | 0 | { |
101 | 0 | const CPLXMLNode *psCodedValues = |
102 | 0 | CPLGetXMLNode(psDomain, "CodedValues"); |
103 | 0 | if (psCodedValues == nullptr) |
104 | 0 | { |
105 | 0 | return nullptr; |
106 | 0 | } |
107 | 0 | std::vector<OGRCodedValue> asValues; |
108 | 0 | for (const CPLXMLNode *psIter = psCodedValues->psChild; psIter; |
109 | 0 | psIter = psIter->psNext) |
110 | 0 | { |
111 | 0 | if (psIter->eType == CXT_Element && |
112 | 0 | strcmp(psIter->pszValue, "CodedValue") == 0) |
113 | 0 | { |
114 | 0 | OGRCodedValue cv; |
115 | 0 | cv.pszCode = CPLStrdup(CPLGetXMLValue(psIter, "Code", "")); |
116 | 0 | cv.pszValue = CPLStrdup(CPLGetXMLValue(psIter, "Name", "")); |
117 | 0 | asValues.emplace_back(cv); |
118 | 0 | } |
119 | 0 | } |
120 | 0 | domain.reset(new OGRCodedFieldDomain(pszName, pszDescription, |
121 | 0 | eFieldType, eSubType, |
122 | 0 | std::move(asValues))); |
123 | 0 | } |
124 | 0 | else if (bIsRangeDomain || strcmp(pszType, "esri:RangeDomain") == 0) |
125 | 0 | { |
126 | 0 | if (eFieldType != OFTInteger && eFieldType != OFTInteger64 && |
127 | 0 | eFieldType != OFTReal && eFieldType != OFTDateTime) |
128 | 0 | { |
129 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
130 | 0 | "Unsupported field type for range domain: %s", |
131 | 0 | pszFieldType); |
132 | 0 | return nullptr; |
133 | 0 | } |
134 | 0 | const char *pszMinValue = CPLGetXMLValue(psDomain, "MinValue", ""); |
135 | 0 | const char *pszMaxValue = CPLGetXMLValue(psDomain, "MaxValue", ""); |
136 | 0 | OGRField sMin; |
137 | 0 | OGRField sMax; |
138 | 0 | OGR_RawField_SetUnset(&sMin); |
139 | 0 | OGR_RawField_SetUnset(&sMax); |
140 | 0 | if (eFieldType == OFTInteger) |
141 | 0 | { |
142 | 0 | sMin.Integer = atoi(pszMinValue); |
143 | 0 | sMax.Integer = atoi(pszMaxValue); |
144 | 0 | } |
145 | 0 | else if (eFieldType == OFTInteger64) |
146 | 0 | { |
147 | 0 | sMin.Integer64 = CPLAtoGIntBig(pszMinValue); |
148 | 0 | sMax.Integer64 = CPLAtoGIntBig(pszMaxValue); |
149 | 0 | } |
150 | 0 | else if (eFieldType == OFTReal) |
151 | 0 | { |
152 | 0 | sMin.Real = CPLAtof(pszMinValue); |
153 | 0 | sMax.Real = CPLAtof(pszMaxValue); |
154 | 0 | } |
155 | 0 | else if (eFieldType == OFTDateTime) |
156 | 0 | { |
157 | 0 | if (!OGRParseXMLDateTime(pszMinValue, &sMin)) |
158 | 0 | { |
159 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Invalid MinValue: %s", |
160 | 0 | pszMinValue); |
161 | 0 | return nullptr; |
162 | 0 | } |
163 | 0 | if (!OGRParseXMLDateTime(pszMaxValue, &sMax)) |
164 | 0 | { |
165 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Invalid MaxValue: %s", |
166 | 0 | pszMaxValue); |
167 | 0 | return nullptr; |
168 | 0 | } |
169 | 0 | } |
170 | 0 | domain.reset(new OGRRangeFieldDomain(pszName, pszDescription, |
171 | 0 | eFieldType, eSubType, sMin, true, |
172 | 0 | sMax, true)); |
173 | 0 | } |
174 | 0 | else |
175 | 0 | { |
176 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
177 | 0 | "Unsupported type of File Geodatabase domain: %s", pszType); |
178 | 0 | return nullptr; |
179 | 0 | } |
180 | | |
181 | 0 | const char *pszMergePolicy = |
182 | 0 | CPLGetXMLValue(psDomain, "MergePolicy", "esriMPTDefaultValue"); |
183 | 0 | if (EQUAL(pszMergePolicy, "esriMPTDefaultValue")) |
184 | 0 | { |
185 | 0 | domain->SetMergePolicy(OFDMP_DEFAULT_VALUE); |
186 | 0 | } |
187 | 0 | else if (EQUAL(pszMergePolicy, "esriMPTSumValues")) |
188 | 0 | { |
189 | 0 | domain->SetMergePolicy(OFDMP_SUM); |
190 | 0 | } |
191 | 0 | else if (EQUAL(pszMergePolicy, "esriMPTAreaWeighted")) |
192 | 0 | { |
193 | 0 | domain->SetMergePolicy(OFDMP_GEOMETRY_WEIGHTED); |
194 | 0 | } |
195 | |
|
196 | 0 | const char *pszSplitPolicy = |
197 | 0 | CPLGetXMLValue(psDomain, "SplitPolicy", "esriSPTDefaultValue"); |
198 | 0 | if (EQUAL(pszSplitPolicy, "esriSPTDefaultValue")) |
199 | 0 | { |
200 | 0 | domain->SetSplitPolicy(OFDSP_DEFAULT_VALUE); |
201 | 0 | } |
202 | 0 | else if (EQUAL(pszSplitPolicy, "esriSPTDuplicate")) |
203 | 0 | { |
204 | 0 | domain->SetSplitPolicy(OFDSP_DUPLICATE); |
205 | 0 | } |
206 | 0 | else if (EQUAL(pszSplitPolicy, "esriSPTGeometryRatio")) |
207 | 0 | { |
208 | 0 | domain->SetSplitPolicy(OFDSP_GEOMETRY_RATIO); |
209 | 0 | } |
210 | |
|
211 | 0 | return domain; |
212 | 0 | } |
213 | | |
214 | | /************************************************************************/ |
215 | | /* BuildXMLFieldDomainDef() */ |
216 | | /************************************************************************/ |
217 | | |
218 | | inline std::string BuildXMLFieldDomainDef(const OGRFieldDomain *poDomain, |
219 | | bool bForFileGDBSDK, |
220 | | std::string &failureReason) |
221 | 0 | { |
222 | 0 | std::string osNS = "esri"; |
223 | 0 | const char *pszRootElt = "esri:Domain"; |
224 | 0 | if (!bForFileGDBSDK) |
225 | 0 | { |
226 | 0 | switch (poDomain->GetDomainType()) |
227 | 0 | { |
228 | 0 | case OFDT_CODED: |
229 | 0 | { |
230 | 0 | pszRootElt = "typens:GPCodedValueDomain2"; |
231 | 0 | break; |
232 | 0 | } |
233 | | |
234 | 0 | case OFDT_RANGE: |
235 | 0 | { |
236 | 0 | pszRootElt = "typens:GPRangeDomain2"; |
237 | 0 | break; |
238 | 0 | } |
239 | | |
240 | 0 | case OFDT_GLOB: |
241 | 0 | { |
242 | 0 | failureReason = |
243 | 0 | "Glob field domain not handled for FileGeoDatabase"; |
244 | 0 | return std::string(); |
245 | 0 | } |
246 | 0 | } |
247 | 0 | osNS = "typens"; |
248 | 0 | } |
249 | | |
250 | 0 | CPLXMLTreeCloser oTree(CPLCreateXMLNode(nullptr, CXT_Element, pszRootElt)); |
251 | 0 | CPLXMLNode *psRoot = oTree.get(); |
252 | |
|
253 | 0 | switch (poDomain->GetDomainType()) |
254 | 0 | { |
255 | 0 | case OFDT_CODED: |
256 | 0 | { |
257 | 0 | CPLAddXMLAttributeAndValue(psRoot, "xsi:type", |
258 | 0 | bForFileGDBSDK |
259 | 0 | ? "esri:CodedValueDomain" |
260 | 0 | : "typens:GPCodedValueDomain2"); |
261 | 0 | break; |
262 | 0 | } |
263 | | |
264 | 0 | case OFDT_RANGE: |
265 | 0 | { |
266 | 0 | CPLAddXMLAttributeAndValue( |
267 | 0 | psRoot, "xsi:type", |
268 | 0 | bForFileGDBSDK ? "esri:RangeDomain" : "typens:GPRangeDomain2"); |
269 | 0 | break; |
270 | 0 | } |
271 | | |
272 | 0 | case OFDT_GLOB: |
273 | 0 | { |
274 | 0 | failureReason = "Glob field domain not handled for FileGeoDatabase"; |
275 | 0 | return std::string(); |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | 0 | CPLAddXMLAttributeAndValue(psRoot, "xmlns:xsi", |
280 | 0 | "http://www.w3.org/2001/XMLSchema-instance"); |
281 | 0 | CPLAddXMLAttributeAndValue(psRoot, "xmlns:xs", |
282 | 0 | "http://www.w3.org/2001/XMLSchema"); |
283 | 0 | CPLAddXMLAttributeAndValue(psRoot, ("xmlns:" + osNS).c_str(), |
284 | 0 | "http://www.esri.com/schemas/ArcGIS/10.1"); |
285 | |
|
286 | 0 | CPLCreateXMLElementAndValue(psRoot, "DomainName", |
287 | 0 | poDomain->GetName().c_str()); |
288 | 0 | if (poDomain->GetFieldType() == OFTInteger) |
289 | 0 | { |
290 | 0 | if (poDomain->GetFieldSubType() == OFSTInt16) |
291 | 0 | CPLCreateXMLElementAndValue(psRoot, "FieldType", |
292 | 0 | "esriFieldTypeSmallInteger"); |
293 | 0 | else |
294 | 0 | CPLCreateXMLElementAndValue(psRoot, "FieldType", |
295 | 0 | "esriFieldTypeInteger"); |
296 | 0 | } |
297 | 0 | else if (poDomain->GetFieldType() == OFTReal) |
298 | 0 | { |
299 | 0 | if (poDomain->GetFieldSubType() == OFSTFloat32) |
300 | 0 | CPLCreateXMLElementAndValue(psRoot, "FieldType", |
301 | 0 | "esriFieldTypeSingle"); |
302 | 0 | else |
303 | 0 | CPLCreateXMLElementAndValue(psRoot, "FieldType", |
304 | 0 | "esriFieldTypeDouble"); |
305 | 0 | } |
306 | 0 | else if (poDomain->GetFieldType() == OFTString) |
307 | 0 | { |
308 | 0 | CPLCreateXMLElementAndValue(psRoot, "FieldType", "esriFieldTypeString"); |
309 | 0 | } |
310 | 0 | else if (poDomain->GetFieldType() == OFTDateTime) |
311 | 0 | { |
312 | 0 | CPLCreateXMLElementAndValue(psRoot, "FieldType", "esriFieldTypeDate"); |
313 | 0 | } |
314 | 0 | else |
315 | 0 | { |
316 | 0 | failureReason = "Unsupported field type for FileGeoDatabase domain"; |
317 | 0 | return std::string(); |
318 | 0 | } |
319 | | |
320 | 0 | switch (poDomain->GetMergePolicy()) |
321 | 0 | { |
322 | 0 | case OFDMP_DEFAULT_VALUE: |
323 | 0 | CPLCreateXMLElementAndValue(psRoot, "MergePolicy", |
324 | 0 | "esriMPTDefaultValue"); |
325 | 0 | break; |
326 | 0 | case OFDMP_SUM: |
327 | 0 | CPLCreateXMLElementAndValue(psRoot, "MergePolicy", |
328 | 0 | "esriMPTSumValues"); |
329 | 0 | break; |
330 | 0 | case OFDMP_GEOMETRY_WEIGHTED: |
331 | 0 | CPLCreateXMLElementAndValue(psRoot, "MergePolicy", |
332 | 0 | "esriMPTAreaWeighted"); |
333 | 0 | break; |
334 | 0 | } |
335 | | |
336 | 0 | switch (poDomain->GetSplitPolicy()) |
337 | 0 | { |
338 | 0 | case OFDSP_DEFAULT_VALUE: |
339 | 0 | CPLCreateXMLElementAndValue(psRoot, "SplitPolicy", |
340 | 0 | "esriSPTDefaultValue"); |
341 | 0 | break; |
342 | 0 | case OFDSP_DUPLICATE: |
343 | 0 | CPLCreateXMLElementAndValue(psRoot, "SplitPolicy", |
344 | 0 | "esriSPTDuplicate"); |
345 | 0 | break; |
346 | 0 | case OFDSP_GEOMETRY_RATIO: |
347 | 0 | CPLCreateXMLElementAndValue(psRoot, "SplitPolicy", |
348 | 0 | "esriSPTGeometryRatio"); |
349 | 0 | break; |
350 | 0 | } |
351 | | |
352 | 0 | CPLCreateXMLElementAndValue(psRoot, "Description", |
353 | 0 | poDomain->GetDescription().c_str()); |
354 | 0 | CPLCreateXMLElementAndValue(psRoot, "Owner", ""); |
355 | |
|
356 | 0 | const auto AddFieldTypeAsXSIType = [&poDomain](CPLXMLNode *psParent) |
357 | 0 | { |
358 | 0 | if (poDomain->GetFieldType() == OFTInteger) |
359 | 0 | { |
360 | 0 | if (poDomain->GetFieldSubType() == OFSTInt16) |
361 | 0 | CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:short"); |
362 | 0 | else |
363 | 0 | CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:int"); |
364 | 0 | } |
365 | 0 | else if (poDomain->GetFieldType() == OFTReal) |
366 | 0 | { |
367 | 0 | if (poDomain->GetFieldSubType() == OFSTFloat32) |
368 | 0 | CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:float"); |
369 | 0 | else |
370 | 0 | CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:double"); |
371 | 0 | } |
372 | 0 | else if (poDomain->GetFieldType() == OFTString) |
373 | 0 | { |
374 | 0 | CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:string"); |
375 | 0 | } |
376 | 0 | else if (poDomain->GetFieldType() == OFTDateTime) |
377 | 0 | { |
378 | 0 | CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:dateTime"); |
379 | 0 | } |
380 | 0 | }; |
381 | |
|
382 | 0 | switch (poDomain->GetDomainType()) |
383 | 0 | { |
384 | 0 | case OFDT_CODED: |
385 | 0 | { |
386 | 0 | auto psCodedValues = |
387 | 0 | CPLCreateXMLNode(psRoot, CXT_Element, "CodedValues"); |
388 | 0 | CPLAddXMLAttributeAndValue(psCodedValues, "xsi:type", |
389 | 0 | (osNS + ":ArrayOfCodedValue").c_str()); |
390 | |
|
391 | 0 | auto poCodedDomain = |
392 | 0 | cpl::down_cast<const OGRCodedFieldDomain *>(poDomain); |
393 | 0 | const OGRCodedValue *psEnumeration = |
394 | 0 | poCodedDomain->GetEnumeration(); |
395 | 0 | for (; psEnumeration->pszCode != nullptr; ++psEnumeration) |
396 | 0 | { |
397 | 0 | auto psCodedValue = |
398 | 0 | CPLCreateXMLNode(psCodedValues, CXT_Element, "CodedValue"); |
399 | 0 | CPLAddXMLAttributeAndValue(psCodedValue, "xsi:type", |
400 | 0 | (osNS + ":CodedValue").c_str()); |
401 | 0 | CPLCreateXMLElementAndValue( |
402 | 0 | psCodedValue, "Name", |
403 | 0 | psEnumeration->pszValue ? psEnumeration->pszValue : ""); |
404 | |
|
405 | 0 | auto psCode = |
406 | 0 | CPLCreateXMLNode(psCodedValue, CXT_Element, "Code"); |
407 | 0 | AddFieldTypeAsXSIType(psCode); |
408 | 0 | CPLCreateXMLNode(psCode, CXT_Text, psEnumeration->pszCode); |
409 | 0 | } |
410 | 0 | break; |
411 | 0 | } |
412 | | |
413 | 0 | case OFDT_RANGE: |
414 | 0 | { |
415 | 0 | auto poRangeDomain = |
416 | 0 | cpl::down_cast<const OGRRangeFieldDomain *>(poDomain); |
417 | |
|
418 | 0 | const auto SerializeMinOrMax = |
419 | 0 | [&AddFieldTypeAsXSIType, &poDomain, |
420 | 0 | psRoot](const char *pszElementName, const OGRField &oValue) |
421 | 0 | { |
422 | 0 | auto psValue = |
423 | 0 | CPLCreateXMLNode(psRoot, CXT_Element, pszElementName); |
424 | 0 | AddFieldTypeAsXSIType(psValue); |
425 | 0 | if (poDomain->GetFieldType() == OFTInteger) |
426 | 0 | { |
427 | 0 | CPLCreateXMLNode(psValue, CXT_Text, |
428 | 0 | CPLSPrintf("%d", oValue.Integer)); |
429 | 0 | } |
430 | 0 | else if (poDomain->GetFieldType() == OFTReal) |
431 | 0 | { |
432 | 0 | CPLCreateXMLNode(psValue, CXT_Text, |
433 | 0 | CPLSPrintf("%.18g", oValue.Real)); |
434 | 0 | } |
435 | 0 | else if (poDomain->GetFieldType() == OFTDateTime) |
436 | 0 | { |
437 | 0 | CPLCreateXMLNode( |
438 | 0 | psValue, CXT_Text, |
439 | 0 | CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02d", |
440 | 0 | oValue.Date.Year, oValue.Date.Month, |
441 | 0 | oValue.Date.Day, oValue.Date.Hour, |
442 | 0 | oValue.Date.Minute, |
443 | 0 | static_cast<int>(oValue.Date.Second + 0.5))); |
444 | 0 | } |
445 | 0 | }; |
446 | |
|
447 | 0 | bool bIsInclusiveOut = false; |
448 | 0 | const OGRField &oMin = poRangeDomain->GetMin(bIsInclusiveOut); |
449 | 0 | const OGRField &oMax = poRangeDomain->GetMax(bIsInclusiveOut); |
450 | 0 | if (OGR_RawField_IsUnset(&oMin) || OGR_RawField_IsUnset(&oMax)) |
451 | 0 | { |
452 | 0 | failureReason = |
453 | 0 | "FileGeoDatabase requires that both minimum and maximum " |
454 | 0 | "values of a range field domain are set."; |
455 | 0 | return std::string(); |
456 | 0 | } |
457 | | |
458 | 0 | SerializeMinOrMax("MaxValue", oMax); |
459 | 0 | SerializeMinOrMax("MinValue", oMin); |
460 | |
|
461 | 0 | break; |
462 | 0 | } |
463 | | |
464 | 0 | case OFDT_GLOB: |
465 | 0 | { |
466 | 0 | CPLAssert(false); |
467 | 0 | break; |
468 | 0 | } |
469 | 0 | } |
470 | | |
471 | 0 | char *pszXML = CPLSerializeXMLTree(oTree.get()); |
472 | 0 | std::string osXML(pszXML); |
473 | 0 | CPLFree(pszXML); |
474 | 0 | return osXML; |
475 | 0 | } |
476 | | |
477 | | #endif // FILEGDB_FIELDDOMAIN_H |