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