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 777 : void GMLASXPathMatcher::SetRefXPaths( 22 : const std::map<CPLString, CPLString> &oMapPrefixToURIReferenceXPaths, 23 : const std::vector<CPLString> &aosReferenceXPaths) 24 : { 25 777 : m_oMapPrefixToURIReferenceXPaths = oMapPrefixToURIReferenceXPaths; 26 777 : m_aosReferenceXPathsUncompiled = aosReferenceXPaths; 27 777 : } 28 : 29 : /************************************************************************/ 30 : /* SetDocumentMapURIToPrefix() */ 31 : /************************************************************************/ 32 : 33 721 : void GMLASXPathMatcher::SetDocumentMapURIToPrefix( 34 : const std::map<CPLString, CPLString> &oMapURIToPrefix) 35 : { 36 721 : m_aosReferenceXPaths.clear(); 37 : 38 : // Split each reference XPath into its components 39 3079 : for (size_t i = 0; i < m_aosReferenceXPathsUncompiled.size(); ++i) 40 : { 41 2358 : const CPLString &osXPath(m_aosReferenceXPathsUncompiled[i]); 42 : 43 4716 : std::vector<XPathComponent> oVector; 44 : 45 2358 : size_t iPos = 0; 46 2358 : bool bDirectChild = false; 47 2358 : if (osXPath.size() >= 2 && osXPath[0] == '/' && osXPath[1] == '/') 48 : { 49 9 : iPos += 2; 50 : } 51 2349 : else if (osXPath.size() >= 1 && osXPath[0] == '/') 52 : { 53 2 : iPos += 1; 54 2 : bDirectChild = true; 55 : } 56 : 57 2941 : while (iPos < osXPath.size()) 58 : { 59 2405 : size_t iPosNextSlash = osXPath.find('/', iPos); 60 : 61 2405 : if (iPos == iPosNextSlash) 62 : { 63 2 : bDirectChild = false; 64 2 : iPos++; 65 2 : continue; 66 : } 67 : 68 2403 : CPLString osCurNode; 69 2403 : if (iPosNextSlash == std::string::npos) 70 1173 : osCurNode.assign(osXPath, iPos, std::string::npos); 71 : else 72 1230 : osCurNode.assign(osXPath, iPos, iPosNextSlash - iPos); 73 : 74 : // Translate the configuration prefix to the equivalent in 75 : // this current schema 76 2403 : size_t iPosColumn = osCurNode.find(':'); 77 2403 : if (iPosColumn != std::string::npos) 78 : { 79 2378 : bool bIsAttr = (osCurNode[0] == '@'); 80 2378 : CPLString osPrefix; 81 2378 : CPLString osLocalname; 82 : osPrefix.assign(osCurNode, bIsAttr ? 1 : 0, 83 2378 : iPosColumn - (bIsAttr ? 1 : 0)); 84 : osLocalname.assign(osCurNode, iPosColumn + 1, 85 2378 : std::string::npos); 86 : 87 : const auto oIter = 88 2378 : m_oMapPrefixToURIReferenceXPaths.find(osPrefix); 89 2378 : if (oIter != m_oMapPrefixToURIReferenceXPaths.end()) 90 : { 91 1879 : const CPLString &osURI(oIter->second); 92 1879 : const auto oIter2 = oMapURIToPrefix.find(osURI); 93 1879 : if (oIter2 == oMapURIToPrefix.end()) 94 1822 : break; 95 57 : osPrefix.assign(oIter2->second); 96 : } 97 : 98 556 : osCurNode.clear(); 99 556 : if (bIsAttr) 100 471 : osCurNode.append(1, '@'); 101 556 : osCurNode.append(osPrefix); 102 556 : osCurNode.append(1, ':'); 103 556 : osCurNode.append(osLocalname); 104 : } 105 : 106 581 : XPathComponent comp; 107 581 : comp.m_osValue = std::move(osCurNode); 108 581 : comp.m_bDirectChild = bDirectChild; 109 581 : oVector.push_back(std::move(comp)); 110 : 111 581 : if (iPosNextSlash == std::string::npos) 112 536 : iPos = osXPath.size(); 113 : else 114 45 : iPos = iPosNextSlash + 1; 115 : 116 581 : bDirectChild = true; 117 : } 118 : 119 2358 : if (iPos < osXPath.size()) 120 1822 : oVector.clear(); 121 2358 : m_aosReferenceXPaths.push_back(std::move(oVector)); 122 : } 123 721 : } 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 205425 : bool GMLASXPathMatcher::MatchesRefXPath( 133 : const CPLString &osXPath, const std::vector<XPathComponent> &oRefXPath) 134 : { 135 205425 : size_t iPos = 0; 136 205425 : size_t iIdxInRef = 0; 137 : 138 205425 : bool bDirectChild = oRefXPath[0].m_bDirectChild; 139 557863 : while (iPos < osXPath.size() && iIdxInRef < oRefXPath.size()) 140 : { 141 554000 : bDirectChild = oRefXPath[iIdxInRef].m_bDirectChild; 142 554000 : size_t iPosNextSlash = osXPath.find('/', iPos); 143 : 144 : bool bNodeMatch; 145 554000 : if (iPosNextSlash == std::string::npos) 146 : { 147 205237 : bNodeMatch = osXPath.compare(iPos, std::string::npos, 148 205237 : oRefXPath[iIdxInRef].m_osValue) == 0; 149 : } 150 : else 151 : { 152 348763 : bNodeMatch = osXPath.compare(iPos, iPosNextSlash - iPos, 153 348763 : oRefXPath[iIdxInRef].m_osValue) == 0; 154 : } 155 : 156 554000 : if (!bNodeMatch) 157 : { 158 548889 : if (bDirectChild) 159 775 : return false; 160 : 161 548114 : if (iPosNextSlash == std::string::npos) 162 200787 : return false; 163 347327 : iPos = iPosNextSlash + 1; 164 347327 : continue; 165 : } 166 : 167 5111 : if (iPosNextSlash == std::string::npos) 168 3861 : iPos = osXPath.size(); 169 : else 170 1250 : iPos = iPosNextSlash + 1; 171 5111 : iIdxInRef++; 172 5111 : bDirectChild = true; 173 : } 174 : 175 7724 : return (!bDirectChild || iPos == osXPath.size()) && 176 7724 : iIdxInRef == oRefXPath.size(); 177 : } 178 : 179 : /************************************************************************/ 180 : /* MatchesRefXPath() */ 181 : /************************************************************************/ 182 : 183 720149 : bool GMLASXPathMatcher::MatchesRefXPath(const CPLString &osXPath, 184 : CPLString &osOutMatchedXPath) const 185 : { 186 1359140 : for (size_t i = 0; i < m_aosReferenceXPaths.size(); ++i) 187 : { 188 848160 : if (!m_aosReferenceXPaths[i].empty() && 189 205425 : MatchesRefXPath(osXPath, m_aosReferenceXPaths[i])) 190 : { 191 3744 : osOutMatchedXPath = m_aosReferenceXPathsUncompiled[i]; 192 3744 : return true; 193 : } 194 : } 195 716405 : return false; 196 : }