Line data Source code
1 : /******************************************************************************
2 : * Project: OGR
3 : * Purpose: OGRGMLASDriver implementation
4 : * Author: Even Rouault, <even dot rouault at spatialys dot com>
5 : *
6 : * Initial development funded by the European Earth observation programme
7 : * Copernicus
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "ogr_gmlas.h"
32 :
33 : /************************************************************************/
34 : /* SetRefXPaths() */
35 : /************************************************************************/
36 :
37 745 : void GMLASXPathMatcher::SetRefXPaths(
38 : const std::map<CPLString, CPLString> &oMapPrefixToURIReferenceXPaths,
39 : const std::vector<CPLString> &aosReferenceXPaths)
40 : {
41 745 : m_oMapPrefixToURIReferenceXPaths = oMapPrefixToURIReferenceXPaths;
42 745 : m_aosReferenceXPathsUncompiled = aosReferenceXPaths;
43 745 : }
44 :
45 : /************************************************************************/
46 : /* SetDocumentMapURIToPrefix() */
47 : /************************************************************************/
48 :
49 689 : void GMLASXPathMatcher::SetDocumentMapURIToPrefix(
50 : const std::map<CPLString, CPLString> &oMapURIToPrefix)
51 : {
52 689 : m_aosReferenceXPaths.clear();
53 :
54 : // Split each reference XPath into its components
55 2847 : for (size_t i = 0; i < m_aosReferenceXPathsUncompiled.size(); ++i)
56 : {
57 2158 : const CPLString &osXPath(m_aosReferenceXPathsUncompiled[i]);
58 :
59 4316 : std::vector<XPathComponent> oVector;
60 :
61 2158 : size_t iPos = 0;
62 2158 : bool bDirectChild = false;
63 2158 : if (osXPath.size() >= 2 && osXPath[0] == '/' && osXPath[1] == '/')
64 : {
65 9 : iPos += 2;
66 : }
67 2149 : else if (osXPath.size() >= 1 && osXPath[0] == '/')
68 : {
69 2 : iPos += 1;
70 2 : bDirectChild = true;
71 : }
72 :
73 2693 : while (iPos < osXPath.size())
74 : {
75 2204 : size_t iPosNextSlash = osXPath.find('/', iPos);
76 :
77 2204 : if (iPos == iPosNextSlash)
78 : {
79 2 : bDirectChild = false;
80 2 : iPos++;
81 2 : continue;
82 : }
83 :
84 2202 : CPLString osCurNode;
85 2202 : if (iPosNextSlash == std::string::npos)
86 1076 : osCurNode.assign(osXPath, iPos, std::string::npos);
87 : else
88 1126 : osCurNode.assign(osXPath, iPos, iPosNextSlash - iPos);
89 :
90 : // Translate the configuration prefix to the equivalent in
91 : // this current schema
92 2202 : size_t iPosColumn = osCurNode.find(':');
93 2202 : if (iPosColumn != std::string::npos)
94 : {
95 2178 : bool bIsAttr = (osCurNode[0] == '@');
96 2178 : CPLString osPrefix;
97 2178 : CPLString osLocalname;
98 : osPrefix.assign(osCurNode, bIsAttr ? 1 : 0,
99 2178 : iPosColumn - (bIsAttr ? 1 : 0));
100 : osLocalname.assign(osCurNode, iPosColumn + 1,
101 2178 : std::string::npos);
102 :
103 : const auto oIter =
104 2178 : m_oMapPrefixToURIReferenceXPaths.find(osPrefix);
105 2178 : if (oIter != m_oMapPrefixToURIReferenceXPaths.end())
106 : {
107 1719 : const CPLString &osURI(oIter->second);
108 1719 : const auto oIter2 = oMapURIToPrefix.find(osURI);
109 1719 : if (oIter2 == oMapURIToPrefix.end())
110 1669 : break;
111 50 : osPrefix.assign(oIter2->second);
112 : }
113 :
114 509 : osCurNode.clear();
115 509 : if (bIsAttr)
116 429 : osCurNode.append(1, '@');
117 509 : osCurNode.append(osPrefix);
118 509 : osCurNode.append(1, ':');
119 509 : osCurNode.append(osLocalname);
120 : }
121 :
122 533 : XPathComponent comp;
123 533 : comp.m_osValue = std::move(osCurNode);
124 533 : comp.m_bDirectChild = bDirectChild;
125 533 : oVector.push_back(comp);
126 :
127 533 : if (iPosNextSlash == std::string::npos)
128 489 : iPos = osXPath.size();
129 : else
130 44 : iPos = iPosNextSlash + 1;
131 :
132 533 : bDirectChild = true;
133 : }
134 :
135 2158 : if (iPos < osXPath.size())
136 1669 : oVector.clear();
137 2158 : m_aosReferenceXPaths.push_back(oVector);
138 : }
139 689 : }
140 :
141 : /************************************************************************/
142 : /* MatchesRefXPath() */
143 : /************************************************************************/
144 :
145 : // This is a performance critical function, especially on geosciml schemas,
146 : // and we make careful to not do any string copy or other memory allocation
147 : // in it.
148 55287 : bool GMLASXPathMatcher::MatchesRefXPath(
149 : const CPLString &osXPath, const std::vector<XPathComponent> &oRefXPath)
150 : {
151 55287 : size_t iPos = 0;
152 55287 : size_t iIdxInRef = 0;
153 :
154 55287 : bool bDirectChild = oRefXPath[0].m_bDirectChild;
155 143242 : while (iPos < osXPath.size() && iIdxInRef < oRefXPath.size())
156 : {
157 142974 : bDirectChild = oRefXPath[iIdxInRef].m_bDirectChild;
158 142974 : size_t iPosNextSlash = osXPath.find('/', iPos);
159 :
160 : bool bNodeMatch;
161 142974 : if (iPosNextSlash == std::string::npos)
162 : {
163 55099 : bNodeMatch = osXPath.compare(iPos, std::string::npos,
164 55099 : oRefXPath[iIdxInRef].m_osValue) == 0;
165 : }
166 : else
167 : {
168 87875 : bNodeMatch = osXPath.compare(iPos, iPosNextSlash - iPos,
169 87875 : oRefXPath[iIdxInRef].m_osValue) == 0;
170 : }
171 :
172 142974 : if (!bNodeMatch)
173 : {
174 141468 : if (bDirectChild)
175 766 : return false;
176 :
177 140702 : if (iPosNextSlash == std::string::npos)
178 54253 : return false;
179 86449 : iPos = iPosNextSlash + 1;
180 86449 : continue;
181 : }
182 :
183 1506 : if (iPosNextSlash == std::string::npos)
184 266 : iPos = osXPath.size();
185 : else
186 1240 : iPos = iPosNextSlash + 1;
187 1506 : iIdxInRef++;
188 1506 : bDirectChild = true;
189 : }
190 :
191 534 : return (!bDirectChild || iPos == osXPath.size()) &&
192 534 : iIdxInRef == oRefXPath.size();
193 : }
194 :
195 : /************************************************************************/
196 : /* MatchesRefXPath() */
197 : /************************************************************************/
198 :
199 693982 : bool GMLASXPathMatcher::MatchesRefXPath(const CPLString &osXPath,
200 : CPLString &osOutMatchedXPath) const
201 : {
202 922232 : for (size_t i = 0; i < m_aosReferenceXPaths.size(); ++i)
203 : {
204 283688 : if (!m_aosReferenceXPaths[i].empty() &&
205 55287 : MatchesRefXPath(osXPath, m_aosReferenceXPaths[i]))
206 : {
207 151 : osOutMatchedXPath = m_aosReferenceXPathsUncompiled[i];
208 151 : return true;
209 : }
210 : }
211 693831 : return false;
212 : }
|