Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying a substring of an attribute in a node and all children

Tags:

xml

xslt

I've done quite a bit of searching and haven't quite been able to come up with anything yet using XSLT. I'm trying to take an XML template (for McPAT, partially shown below) dictating system specs and duplicate the component id="system.core0" name="core0" node so I can have N core nodes. Each one will have to have "system.core#" as the id and "core#" as the name with # being the core number, 0-n.

I also have to duplicate this in any descendant nodes such as the system.core0.itlb node below.

Even further, in any of the descendant nodes with a value such as "config.system.cpu.clock", I have to append the node number to "cpu."

Finally, I have to overwrite param name="number_of_cores" value="1" under system with param name="number_of_cores" value="n" and change param name="homogenous_cores" value="1" to param name="homogenous_cores" value="0"

The XML currently looks like this:

<?xml version="1.0" ?>
<component id="root" name="root">
    <component id="system" name="system">
         <param name="number_of_cores" value="1"/>
         <param name="homogeneous_cores" value="1"/>
         <param name="number_of_L1Directories" value="0"/>
         <param name="number_of_L2Directories" value="0"/>
         <param name="number_of_L2s" value="1"/> 
         <param name="Private_L2" value="0"/>
         <param name="number_of_L3s" value="0"/> 
         <param name="number_of_NoCs" value="1"/>
         ...
         <component id="system.core0" name="core0">
             <!-- Core property -->
             <param name="clock_rate" value="{1e-6/config.system.cpu.clock*1e12}"/>
             <param name="opt_local" value="1"/>      
             <stat name="total_instructions" value="{stats.system.cpu.iq.iqInstsIssued}"/>

             ...
             <component id="system.core0.itlb" name="itlb">
                 <param name="number_entries" value="{config.system.cpu.itb.size}"/>
                 <stat name="total_accesses" value="{stats.system.cpu.itb.fetch_accesses}"/>
                 ...
             </component>
         </component>
     </component>
 </component>

There are quite a few lines here. I've already gone and copied the system.core0 node N times, thanks to SO. I would post the link but I can't find the page. I do know that Dimitre Novatchev put the answer that I followed though and I'd like to give him credit for his help with that. So far, the XSLT stylesheet looks like this:

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

    <xsl:param name="n" select="5"/>

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

    <xsl:template match="component[@id='system']/component[@name='core0']">
        <xsl:call-template name="copyNtimes">
            <xsl:with-param name="n" select="$n"/>
            <xsl:with-param name="core_num" select="1"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="copyNtimes">
        <xsl:param name="n" select="0"/>
        <xsl:param name="core_num" select="1"/>

        <xsl:if test="$n > 0">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
            <xsl:text>
            </xsl:text>
            <xsl:call-template name="copyNtimes">
                <xsl:with-param name="n" select="$n -1"/>
                <xsl:with-param name="core_num" select="$core_num+1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

So at the end of running this through xsltproc, I have the original with system.core0 duplicated N times. What's left has been driving me crazy for days. How do I go about changing the core numbers for each new node I create, reflecting that in all child nodes as well? Any help at all would help, even if it's not code. I've played around with making new templates and using copy-of but nothing seems to be getting me closer.

I could also bring this all into another language such as Perl where I can run the XSLT stylesheet to duplicate change and manually modify the attribute strings if that'd be easier. I know Perl has some pretty good modules for both XML and XSLT. I feel that XSLT should be able to do this,though, and since I'm new to it, the format is throwing me off.

Edit: An example output of what I need is something like this:

<?xml version="1.0" ?>
    <component id="root" name="root">
        <component id="system" name="system">
             <param name="number_of_cores" value="3"/>
             <param name="homogeneous_cores" value="0"/>
             <param name="number_of_L1Directories" value="0"/>
             <param name="number_of_L2Directories" value="0"/>
             <param name="number_of_L2s" value="1"/> 
             <param name="Private_L2" value="0"/>
             <param name="number_of_L3s" value="0"/> 
             <param name="number_of_NoCs" value="1"/>
             <!--...-->
             <component id="system.core0" name="core0">
                 <!-- Core property -->
                 <param name="clock_rate" value="{1e-6/config.system.cpu0.clock*1e12}"/>
                 <param name="opt_local" value="1"/>      
                 <stat name="total_instructions" value="{stats.system.cpu0.iq.iqInstsIssued}"/>
                 <!--...-->
                 <component id="system.core0.itlb" name="itlb">
                     <param name="number_entries" value="{config.system.cpu0.itb.size}"/>
                     <stat name="total_accesses" value="{stats.system.cpu0.itb.fetch_accesses}"/>
                     ...
                 </component>
             </component>
             <component id="system.core1" name="core1">
                 <!-- Core property -->
                 <param name="clock_rate" value="{1e-6/config.system.cpu1.clock*1e12}"/>
                 <param name="opt_local" value="1"/>      
                 <stat name="total_instructions" value="{stats.system.cpu1.iq.iqInstsIssued}"/>
                 <!--...-->
                 <component id="system.core1.itlb" name="itlb">
                     <param name="number_entries" value="{config.system.cpu1.itb.size}"/>
                     <stat name="total_accesses" value="{stats.system.cpu1.itb.fetch_accesses}"/>
                     ...
                 </component>
             </component><component id="system.core2" name="core2">
                 <!-- Core property -->
                 <param name="clock_rate" value="{1e-6/config.system.cpu2.clock*1e12}"/>
                 <param name="opt_local" value="1"/>      
                 <stat name="total_instructions" value="{stats.system.cpu2.iq.iqInstsIssued}"/>
                 <!--...-->
                 <component id="system.core2.itlb" name="itlb">
                     <param name="number_entries" value="{config.system.cpu2.itb.size}"/>
                     <stat name="total_accesses" value="{stats.system.cpu2.itb.fetch_accesses}"/>
                     ...
                 </component>
             </component>
         </component>
     </component>
like image 350
Dave Kindel Avatar asked Oct 21 '22 01:10

Dave Kindel


1 Answers

(1) If you add the following two templates to your XSLT,

  <xsl:template match="param[@name='number_of_cores' and @value='1']">
    <param name="number_of_cores" value="{$n}"/>
  </xsl:template>

  <xsl:template match="param[@name='homogeneous_cores' and @value='1']">
    <param name="homogenous_cores" value="0"/>
  </xsl:template>

you will override the identity transformation and be able to output different param elements as illustrated above.

(2) If you adjust the copying within copyNtimes as follows,

  <xsl:copy>
    <xsl:attribute name="id" select="concat('system.core', $n)"/>
    <xsl:attribute name="name" select="concat('core', $n)"/>
    <xsl:apply-templates select="node()"/>
  </xsl:copy>

you will generate not carbon copies but copies where @id and @name reflect the copy number passed to copyNtimes.

(3) If you further adjust the xsl:apply-template in copyNtimes to tunnel n (XSLT 2.0 required),

  <xsl:apply-templates select="node()">
    <xsl:with-param name="compNum" tunnel="yes" select="$n"/>
  </xsl:apply-templates>

and also add a template to handle itlb components on the other side of the tunnel,

  <xsl:template match="component[@name='itlb']">
    <xsl:param name="compNum" tunnel="yes"/>
    <component name="itlb" value="{concat('system.core',$compNum,'.itlb')}">
      <xsl:apply-templates/>
    </component>
  </xsl:template>

you can work the component number into the descendent itlb components.

Updated (for a third time) complete code and sample input/output XML documents follow...

This input XML document:

<?xml version="1.0" ?>
<component id="root" name="root">
  <component id="system" name="system">
    <param name="number_of_cores" value="1"/>
    <param name="homogeneous_cores" value="1"/>
    <param name="number_of_L1Directories" value="0"/>
    <param name="number_of_L2Directories" value="0"/>
    <param name="number_of_L2s" value="1"/> 
    <param name="Private_L2" value="0"/>
    <param name="number_of_L3s" value="0"/> 
    <param name="number_of_NoCs" value="1"/>
    <!-- ... -->
    <component id="system.core0" name="core0">
      <!-- Core property -->
      <param name="clock_rate" value="{1e-6/config.system.cpu.clock*1e12}"/>
      <param name="opt_local" value="1"/>      
      <stat name="total_instructions" value="{stats.system.cpu.iq.iqInstsIssued}"/>

      <!-- ... -->
      <component id="system.core0.itlb" name="itlb">
        <param name="number_entries" value="{config.system.cpu.itb.size}"/>
        <stat name="total_accesses" value="{stats.system.cpu.itb.fetch_accesses}"/>
        <!-- ... -->
      </component>
    </component>
  </component>
</component>

Given to this XSLT transformation:

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

  <xsl:param name="n" select="5"/>

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

  <xsl:template match="param[@name='number_of_cores' and @value='1']">
    <param name="number_of_cores" value="{$n}"/>
  </xsl:template>

  <xsl:template match="param[@name='homogeneous_cores' and @value='1']">
    <param name="homogenous_cores" value="0"/>
  </xsl:template>

  <xsl:template match="component[@name='itlb']">
    <xsl:param name="compNum" tunnel="yes"/>
    <component name="itlb" value="{concat('system.core',$compNum,'.itlb')}">
      <xsl:apply-templates/>
    </component>
  </xsl:template>

  <xsl:template match="component[@id='system']/component[@name='core0']">
    <xsl:call-template name="copyNtimes">
      <xsl:with-param name="n" select="$n"/>
      <xsl:with-param name="core_num" select="1"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="copyNtimes">
    <xsl:param name="n" select="0"/>
    <xsl:param name="core_num" select="1"/>

    <xsl:if test="$n > 0">
      <xsl:copy>
        <xsl:attribute name="id" select="concat('system.core', $n)"/>
        <xsl:attribute name="name" select="concat('core', $n)"/>
        <xsl:apply-templates select="node()">
          <xsl:with-param name="compNum" tunnel="yes" select="$n"/>
        </xsl:apply-templates>
      </xsl:copy>
      <xsl:text>
      </xsl:text>
      <xsl:call-template name="copyNtimes">
        <xsl:with-param name="n" select="$n -1"/>
        <xsl:with-param name="core_num" select="$core_num+1"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

Will yield this output XML document:

<?xml version="1.0" encoding="UTF-8"?>
<component id="root" name="root">
  <component id="system" name="system">
      <param name="number_of_cores" value="5"/>
      <param name="homogenous_cores" value="0"/>
      <param name="number_of_L1Directories" value="0"/>
      <param name="number_of_L2Directories" value="0"/>
      <param name="number_of_L2s" value="1"/> 
      <param name="Private_L2" value="0"/>
      <param name="number_of_L3s" value="0"/> 
      <param name="number_of_NoCs" value="1"/>
      <!-- ... -->
      <component id="system.core5" name="core5">
      <!-- Core property -->
         <param name="clock_rate" value="{1e-6/config.system.cpu.clock*1e12}"/>
         <param name="opt_local" value="1"/>      
         <stat name="total_instructions" value="{stats.system.cpu.iq.iqInstsIssued}"/>

         <!-- ... -->
         <component name="itlb" value="system.core5.itlb">
            <param name="number_entries" value="{config.system.cpu.itb.size}"/>
            <stat name="total_accesses" value="{stats.system.cpu.itb.fetch_accesses}"/>
            <!-- ... -->
         </component>
      </component>
      <component id="system.core4" name="core4">
      <!-- Core property -->
         <param name="clock_rate" value="{1e-6/config.system.cpu.clock*1e12}"/>
         <param name="opt_local" value="1"/>      
         <stat name="total_instructions" value="{stats.system.cpu.iq.iqInstsIssued}"/>

         <!-- ... -->
         <component name="itlb" value="system.core4.itlb">
            <param name="number_entries" value="{config.system.cpu.itb.size}"/>
            <stat name="total_accesses" value="{stats.system.cpu.itb.fetch_accesses}"/>
            <!-- ... -->
         </component>
      </component>
      <component id="system.core3" name="core3">
      <!-- Core property -->
         <param name="clock_rate" value="{1e-6/config.system.cpu.clock*1e12}"/>
         <param name="opt_local" value="1"/>      
         <stat name="total_instructions" value="{stats.system.cpu.iq.iqInstsIssued}"/>

         <!-- ... -->
         <component name="itlb" value="system.core3.itlb">
            <param name="number_entries" value="{config.system.cpu.itb.size}"/>
            <stat name="total_accesses" value="{stats.system.cpu.itb.fetch_accesses}"/>
            <!-- ... -->
         </component>
      </component>
      <component id="system.core2" name="core2">
      <!-- Core property -->
         <param name="clock_rate" value="{1e-6/config.system.cpu.clock*1e12}"/>
         <param name="opt_local" value="1"/>      
         <stat name="total_instructions" value="{stats.system.cpu.iq.iqInstsIssued}"/>

         <!-- ... -->
         <component name="itlb" value="system.core2.itlb">
            <param name="number_entries" value="{config.system.cpu.itb.size}"/>
            <stat name="total_accesses" value="{stats.system.cpu.itb.fetch_accesses}"/>
            <!-- ... -->
         </component>
      </component>
      <component id="system.core1" name="core1">
      <!-- Core property -->
         <param name="clock_rate" value="{1e-6/config.system.cpu.clock*1e12}"/>
         <param name="opt_local" value="1"/>      
         <stat name="total_instructions" value="{stats.system.cpu.iq.iqInstsIssued}"/>

         <!-- ... -->
         <component name="itlb" value="system.core1.itlb">
            <param name="number_entries" value="{config.system.cpu.itb.size}"/>
            <stat name="total_accesses" value="{stats.system.cpu.itb.fetch_accesses}"/>
            <!-- ... -->
         </component>
      </component>

  </component>
</component>
like image 103
kjhughes Avatar answered Oct 23 '22 02:10

kjhughes