LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlas - ogrgmlasxpatchmatcher.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 91 91 100.0 %
Date: 2024-05-06 13:02:59 Functions: 4 4 100.0 %

          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             : }

Generated by: LCOV version 1.14