Blob Blame History Raw
<?xml version="1.0" encoding="UTF-8"?>

<!--
Copyright 2012 Red Hat Inc., Durham, North Carolina.
All Rights Reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
 
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.
 
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
Authors:
      Martin Preisler <mpreisle@redhat.com>
-->

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xccdf_11="http://checklists.nist.gov/xccdf/1.1"
  xmlns:xccdf_12="http://checklists.nist.gov/xccdf/1.2"

  version="1.0">
 
  <xsl:output method="xml" indent="yes"/>

  <xsl:param name="reverse_DNS"/>

  <xsl:key name="profiles" match="/xccdf_11:Benchmark/xccdf_11:Profile" use="@id"/>
  <xsl:key name="rules" match="/xccdf_11:Benchmark//xccdf_11:Rule" use="@id"/>
  <xsl:key name="groups" match="/xccdf_11:Benchmark//xccdf_11:Group" use="@id"/>
  <xsl:key name="values" match="/xccdf_11:Benchmark//xccdf_11:Value" use="@id"/>

  <!-- This is the generic matched template that by default copies everything
       verbatim, every template that is more specifically matched that this
       will take precedence -->  
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- Deals with namespace change (xccdf 1.1 -> xccdf 1.2) -->
  <xsl:template match="xccdf_11:*"> <!-- select just elements from xccdf 1.1 -->
    <xsl:choose>
      <!-- Remove deprecated elements -->
      <xsl:when test="local-name()='platform-definitions' or local-name()='Platform-Specification' or local-name()='cpe-list' or local-name()='impact-metric'">
        <!-- We will do a trick here to "comment" the deprecated elements,
             XSLT itself ignores all nodes inside <xsl:comment> except TEXT
             nodes, so we can't use that. -->
        <xsl:text disable-output-escaping="yes">&lt;--</xsl:text>
        This element has been deprecated and was removed from XCCDF 1.2!

        <xsl:element name="{local-name()}">
          <xsl:apply-templates select="@*"/>
          <xsl:apply-templates/>
        </xsl:element>
        <xsl:text disable-output-escaping="yes">--&gt;</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:element name="{local-name()}" namespace="http://checklists.nist.gov/xccdf/1.2">
          <!-- We have basically added an element with the same local name but xccdf 1.2 namespace,
               now we want to apply templates to all attributes of it and all subelements -->
          <xsl:apply-templates select="@*"/>
          <xsl:apply-templates/>
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Deals with the new enforced id format of Benchmark -->
  <xsl:template match="@id[parent::xccdf_11:Benchmark]"> 
    <xsl:variable name="old_id" select="."/>

    <xsl:attribute name="id">
      <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_benchmark_', $old_id)"/>
    </xsl:attribute>
  </xsl:template>

  <!-- Deals with the new enforced id format of Rule -->
  <xsl:template match="@id[parent::xccdf_11:Profile]">
    <xsl:variable name="old_id" select="."/>

    <xsl:attribute name="id">
      <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_profile_', $old_id)"/>
    </xsl:attribute>
  </xsl:template>

  <!-- Deals with the new enforced id format of Rule -->
  <xsl:template match="@id[parent::xccdf_11:Rule]">
    <xsl:variable name="old_id" select="."/>

    <xsl:attribute name="id">
      <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_rule_', $old_id)"/>
    </xsl:attribute>
  </xsl:template>

  <!-- Deals with the new enforced id format of Group -->
  <xsl:template match="@id[parent::xccdf_11:Group]">
    <xsl:variable name="old_id" select="."/>

    <xsl:attribute name="id">
      <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_group_', $old_id)"/>
    </xsl:attribute>
  </xsl:template>

  <!-- Deals with the new enforced id format of Value -->
  <xsl:template match="@id[parent::xccdf_11:Value]">
    <xsl:variable name="old_id" select="."/>

    <xsl:attribute name="id">
      <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_value_', $old_id)"/>
    </xsl:attribute>
  </xsl:template>

  <!-- Deals with the new enforced id format of TestResult -->
  <xsl:template match="@id[parent::xccdf_11:TestResult]">
    <xsl:variable name="old_id" select="."/>

    <xsl:attribute name="id">
      <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_testresult_', $old_id)"/>
    </xsl:attribute>
  </xsl:template>

  <!-- Change style from SCAP_1.1 to SCAP_1.2 -->
  <xsl:template match="@style[parent::xccdf_11:Benchmark][.='SCAP_1.1']">
    <xsl:attribute name="style">SCAP_1.2</xsl:attribute>
  </xsl:template>

  <!-- idrefs -->
  <!-- we want to migrate all @idrefs except platform's, we don't migrate requires/@idref here, it's handled elsewhere -->
  <xsl:template match="@idref[parent::xccdf_11:*][not(parent::xccdf_11:platform)][not(parent::xccdf_11:requires)]">
    <xsl:variable name="old_idref" select="."/>

    <xsl:attribute name="idref">
      <!-- Our goal here is to figure out which item the idref references and
           change its format accordingly -->

      <xsl:choose>
        <xsl:when test="key('profiles', $old_idref)">
          <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_profile_', $old_idref)"/>
        </xsl:when>

        <xsl:when test="key('rules', $old_idref)">
          <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_rule_', $old_idref)"/>
        </xsl:when>

        <xsl:when test="key('groups', $old_idref)">
          <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_group_', $old_idref)"/>
        </xsl:when>

        <xsl:when test="key('values', $old_idref)">
          <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_value_', $old_idref)"/>
        </xsl:when>
        
        <xsl:otherwise>
          <xsl:value-of select="concat('dangling reference to ', $old_idref, '!')"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
  </xsl:template>
 
  <xsl:template name="migrate-requires">
    <!-- The string parameter represents text content of the requires attribute
         It needs to have ' ' appended for this template to work! -->

    <xsl:param name="string"/>
    <xsl:choose>
      <!-- requires contain space delimited references, we will strip them one by one -->
      <xsl:when test="$string=''">
        <!-- we are done -->
      </xsl:when>
      <xsl:otherwise>
        <xsl:choose>
          <xsl:when test="key('groups', substring-before($string, ' '))">
           <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_group_', substring-before($string, ' '))"/>
          </xsl:when>
          <xsl:when test="key('rules', substring-before($string, ' '))">
            <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_rule_', substring-before($string, ' '))"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="concat('dangling reference to ', substring-before($string, ' '), '!')"/>
          </xsl:otherwise>
        </xsl:choose>
        
        <!-- we test whether the tail is empty to avoid inserting one extra space -->
        <xsl:variable name="tail" select="substring-after($string, ' ')"/>
        <xsl:if test="$tail!=''">
          <xsl:text> </xsl:text>
          <xsl:call-template name="migrate-requires">
            <xsl:with-param name="string" select="$tail"/>
          </xsl:call-template>
        </xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="@idref[parent::xccdf_11:requires]">
    <!-- We intentionally concat @idref and a space, this is required for the called template to work properly -->
    <xsl:variable name="old_idref" select="."/>
    <xsl:attribute name="idref"><xsl:call-template name="migrate-requires"><xsl:with-param name="string" select="concat($old_idref, ' ')"/></xsl:call-template></xsl:attribute>
  </xsl:template>

  <!-- value-ids -->
  <xsl:template match="@value-id[parent::xccdf_11:*]">
    <xsl:variable name="old_value_id" select="."/>

    <xsl:attribute name="value-id">
      <!-- Our goal here is to figure out which item the value-id references and
           change its format accordingly -->

      <xsl:choose>
        <xsl:when test="key('values', $old_value_id)">
          <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_value_', $old_value_id)"/>
        </xsl:when>

        <xsl:otherwise>
          <xsl:value-of select="concat('dangling reference to ', $old_value_id, '!')"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
  </xsl:template>

  <!-- Group/@extends -->
  <!-- If present, update extends attribute -->
  <xsl:template match="@extends[parent::xccdf_11:Group]">
    <xsl:variable name="old_extends" select="."/>

    <xsl:attribute name="extends">
      <xsl:choose>
       <xsl:when test="key('groups', $old_extends)">
          <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_group_', $old_extends)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="concat('dangling reference to ', $old_extends, '!')"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
  </xsl:template>

  <!-- Rule/@extends -->
  <!-- If present, update extends attribute -->
  <xsl:template match="@extends[parent::xccdf_11:Rule]">
    <xsl:variable name="old_extends" select="."/>

    <xsl:attribute name="extends">
      <xsl:choose>
       <xsl:when test="key('rules', $old_extends)">
          <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_rule_', $old_extends)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="concat('dangling reference to ', $old_extends, '!')"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
  </xsl:template>

  <!-- Value/@extends -->
  <!-- If present, update extends attribute -->
  <xsl:template match="@extends[parent::xccdf_11:Value]">
    <xsl:variable name="old_extends" select="."/>

    <xsl:attribute name="extends">
      <xsl:choose>
       <xsl:when test="key('values', $old_extends)">
          <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_value_', $old_extends)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="concat('dangling reference to ', $old_extends, '!')"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
  </xsl:template>

  <!-- Profile/@extends -->
  <!-- If present, update extends attribute -->
  <xsl:template match="@extends[parent::xccdf_11:Profile]">
    <xsl:variable name="old_extends" select="."/>

    <xsl:attribute name="extends">
      <xsl:choose>
       <xsl:when test="key('profiles', $old_extends)">
          <xsl:value-of select="concat('xccdf_', $reverse_DNS, '_profile_', $old_extends)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="concat('dangling reference to ', $old_extends, '!')"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
  </xsl:template>

  <!-- add the @legacy attribute to <sub> elements -->
  <xsl:template match="xccdf_11:sub">
    <xsl:element name="{local-name()}" namespace="http://checklists.nist.gov/xccdf/1.2">
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates/>
      <xsl:attribute name="use">legacy</xsl:attribute>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>