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: 2025-01-18 12:42:00 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             :  * 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             : }

Generated by: LCOV version 1.14