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-05-31 00:00:17 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         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             : }

Generated by: LCOV version 1.14