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 : * SPDX-License-Identifier: MIT 13 : ****************************************************************************/ 14 : 15 : #include "ogr_gmlas.h" 16 : 17 : /************************************************************************/ 18 : /* SetRefXPaths() */ 19 : /************************************************************************/ 20 : 21 757 : void GMLASXPathMatcher::SetRefXPaths( 22 : const std::map<CPLString, CPLString> &oMapPrefixToURIReferenceXPaths, 23 : const std::vector<CPLString> &aosReferenceXPaths) 24 : { 25 757 : m_oMapPrefixToURIReferenceXPaths = oMapPrefixToURIReferenceXPaths; 26 757 : m_aosReferenceXPathsUncompiled = aosReferenceXPaths; 27 757 : } 28 : 29 : /************************************************************************/ 30 : /* SetDocumentMapURIToPrefix() */ 31 : /************************************************************************/ 32 : 33 701 : void GMLASXPathMatcher::SetDocumentMapURIToPrefix( 34 : const std::map<CPLString, CPLString> &oMapURIToPrefix) 35 : { 36 701 : m_aosReferenceXPaths.clear(); 37 : 38 : // Split each reference XPath into its components 39 2934 : for (size_t i = 0; i < m_aosReferenceXPathsUncompiled.size(); ++i) 40 : { 41 2233 : const CPLString &osXPath(m_aosReferenceXPathsUncompiled[i]); 42 : 43 4466 : std::vector<XPathComponent> oVector; 44 : 45 2233 : size_t iPos = 0; 46 2233 : bool bDirectChild = false; 47 2233 : if (osXPath.size() >= 2 && osXPath[0] == '/' && osXPath[1] == '/') 48 : { 49 9 : iPos += 2; 50 : } 51 2224 : else if (osXPath.size() >= 1 && osXPath[0] == '/') 52 : { 53 2 : iPos += 1; 54 2 : bDirectChild = true; 55 : } 56 : 57 2788 : while (iPos < osXPath.size()) 58 : { 59 2280 : size_t iPosNextSlash = osXPath.find('/', iPos); 60 : 61 2280 : if (iPos == iPosNextSlash) 62 : { 63 2 : bDirectChild = false; 64 2 : iPos++; 65 2 : continue; 66 : } 67 : 68 2278 : CPLString osCurNode; 69 2278 : if (iPosNextSlash == std::string::npos) 70 1113 : osCurNode.assign(osXPath, iPos, std::string::npos); 71 : else 72 1165 : osCurNode.assign(osXPath, iPos, iPosNextSlash - iPos); 73 : 74 : // Translate the configuration prefix to the equivalent in 75 : // this current schema 76 2278 : size_t iPosColumn = osCurNode.find(':'); 77 2278 : if (iPosColumn != std::string::npos) 78 : { 79 2253 : bool bIsAttr = (osCurNode[0] == '@'); 80 2253 : CPLString osPrefix; 81 2253 : CPLString osLocalname; 82 : osPrefix.assign(osCurNode, bIsAttr ? 1 : 0, 83 2253 : iPosColumn - (bIsAttr ? 1 : 0)); 84 : osLocalname.assign(osCurNode, iPosColumn + 1, 85 2253 : std::string::npos); 86 : 87 : const auto oIter = 88 2253 : m_oMapPrefixToURIReferenceXPaths.find(osPrefix); 89 2253 : if (oIter != m_oMapPrefixToURIReferenceXPaths.end()) 90 : { 91 1779 : const CPLString &osURI(oIter->second); 92 1779 : const auto oIter2 = oMapURIToPrefix.find(osURI); 93 1779 : if (oIter2 == oMapURIToPrefix.end()) 94 1725 : break; 95 54 : osPrefix.assign(oIter2->second); 96 : } 97 : 98 528 : osCurNode.clear(); 99 528 : if (bIsAttr) 100 445 : osCurNode.append(1, '@'); 101 528 : osCurNode.append(osPrefix); 102 528 : osCurNode.append(1, ':'); 103 528 : osCurNode.append(osLocalname); 104 : } 105 : 106 553 : XPathComponent comp; 107 553 : comp.m_osValue = std::move(osCurNode); 108 553 : comp.m_bDirectChild = bDirectChild; 109 553 : oVector.push_back(comp); 110 : 111 553 : if (iPosNextSlash == std::string::npos) 112 508 : iPos = osXPath.size(); 113 : else 114 45 : iPos = iPosNextSlash + 1; 115 : 116 553 : bDirectChild = true; 117 : } 118 : 119 2233 : if (iPos < osXPath.size()) 120 1725 : oVector.clear(); 121 2233 : m_aosReferenceXPaths.push_back(oVector); 122 : } 123 701 : } 124 : 125 : /************************************************************************/ 126 : /* MatchesRefXPath() */ 127 : /************************************************************************/ 128 : 129 : // This is a performance critical function, especially on geosciml schemas, 130 : // and we make careful to not do any string copy or other memory allocation 131 : // in it. 132 57460 : bool GMLASXPathMatcher::MatchesRefXPath( 133 : const CPLString &osXPath, const std::vector<XPathComponent> &oRefXPath) 134 : { 135 57460 : size_t iPos = 0; 136 57460 : size_t iIdxInRef = 0; 137 : 138 57460 : bool bDirectChild = oRefXPath[0].m_bDirectChild; 139 148282 : while (iPos < osXPath.size() && iIdxInRef < oRefXPath.size()) 140 : { 141 147965 : bDirectChild = oRefXPath[iIdxInRef].m_bDirectChild; 142 147965 : size_t iPosNextSlash = osXPath.find('/', iPos); 143 : 144 : bool bNodeMatch; 145 147965 : if (iPosNextSlash == std::string::npos) 146 : { 147 57272 : bNodeMatch = osXPath.compare(iPos, std::string::npos, 148 57272 : oRefXPath[iIdxInRef].m_osValue) == 0; 149 : } 150 : else 151 : { 152 90693 : bNodeMatch = osXPath.compare(iPos, iPosNextSlash - iPos, 153 90693 : oRefXPath[iIdxInRef].m_osValue) == 0; 154 : } 155 : 156 147965 : if (!bNodeMatch) 157 : { 158 146400 : if (bDirectChild) 159 775 : return false; 160 : 161 145625 : if (iPosNextSlash == std::string::npos) 162 56368 : return false; 163 89257 : iPos = iPosNextSlash + 1; 164 89257 : continue; 165 : } 166 : 167 1565 : if (iPosNextSlash == std::string::npos) 168 315 : iPos = osXPath.size(); 169 : else 170 1250 : iPos = iPosNextSlash + 1; 171 1565 : iIdxInRef++; 172 1565 : bDirectChild = true; 173 : } 174 : 175 632 : return (!bDirectChild || iPos == osXPath.size()) && 176 632 : iIdxInRef == oRefXPath.size(); 177 : } 178 : 179 : /************************************************************************/ 180 : /* MatchesRefXPath() */ 181 : /************************************************************************/ 182 : 183 694640 : bool GMLASXPathMatcher::MatchesRefXPath(const CPLString &osXPath, 184 : CPLString &osOutMatchedXPath) const 185 : { 186 930985 : for (size_t i = 0; i < m_aosReferenceXPaths.size(); ++i) 187 : { 188 294003 : if (!m_aosReferenceXPaths[i].empty() && 189 57460 : MatchesRefXPath(osXPath, m_aosReferenceXPaths[i])) 190 : { 191 198 : osOutMatchedXPath = m_aosReferenceXPathsUncompiled[i]; 192 198 : return true; 193 : } 194 : } 195 694442 : return false; 196 : }