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-11-21 22:18:42 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         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             : }

Generated by: LCOV version 1.14