Home > front end >  xslt: remove attribute when parent node has an attribute matching a pattern (filter out branch cover
xslt: remove attribute when parent node has an attribute matching a pattern (filter out branch cover

Time:03-16

I am producing coverage reports using gcovr for import into sonar. This use this format (https://docs.sonarqube.org/latest/analysis/generic-test/):

<coverage version="1">
 <file path="src/hello.cpp">
  <lineToCover lineNumber="6" covered="true"/>
  <lineToCover lineNumber="7" covered="false" branchesToCover="2" coveredBranches="1"/>
 </file>
 <file path="test/helloTest.cpp">
  <lineToCover lineNumber="3" covered="true" branchesToCover="2" coveredBranches="1"/>
 </file>
</coverage>

I want to include line coverage for all files but I want to eliminate branch coverage for test code as it only the 'happy' branch is executed. Keeping line coverage in shows redundant code for tests that are never executed. A bit like this issue - https://github.com/gcovr/gcovr/issues/482

Basically I want to say:

  • If the path attribute matches the pattern test/* then
  • remove the branchesToCover and coveredBranches attributes from the children

So for the above the output would become:

<coverage version="1">
 <file path="src/hello.cpp">
  <lineToCover lineNumber="6" covered="true"/>
  <lineToCover lineNumber="7" covered="false" branchesToCover="2" coveredBranches="1"/>
 </file>
 <file path="test/helloTest.cpp">
  <lineToCover lineNumber="3" covered="true"/>
 </file>
</coverage>

This seems like an ideal candidate for XSLT. Unfortunately, this is a skill I have not yet acquired.

I have been able to work out how to remove the attributes for all elements but not how to restrict it to the case where the path attribute in the (parent) file element matches some criteria.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="@branchesToCover"/>
   <xsl:template match="@coveredBranches"/>
</xsl:stylesheet>

It would be helpful and educational if someone could explain how to do this or point me in the right direction. I guess it could be some combinations of the answers to these kinds of question:

CodePudding user response:

This is one way this could be done :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    version="1.0">

  <xsl:output method="xml" indent="yes"/>
  
  <!-- Identity transform -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- Remove branchesToCover attribute when file/@path starts with 'test' -->
  <xsl:template match="@branchesToCover[starts-with(ancestor::file/@path,'test')]"/>
  
  <!-- Remove coveredBranches attribute when file/@path starts with 'test' -->  
  <xsl:template match="@coveredBranches[starts-with(ancestor::file/@path,'test')]"/>
  
</xsl:stylesheet>

See it working here : https://xsltfiddle.liberty-development.net/nbspVbj

CodePudding user response:

I would suggest you do:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="file[starts-with(@path, 'test/')]/lineToCover">
    <xsl:copy>
        <xsl:copy-of select="@lineNumber | @covered"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

CodePudding user response:

Another option just for fun...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="file[starts-with(@path,'test/')]/lineToCover/@*[name()='branchesToCover' or name()='coveredBranches']"/>
    
</xsl:stylesheet>
  • Related