简体   繁体   中英

convert XSLT code from version 2.0 to 1.0

There is xslt code for version 2.0 which gives output shown below but I want to convert it to version 1.0. I referred following links.. How to compare two XML nodes and get compared result using XSLT? and xslt compare two different nodes and then combine

Input XML file:

<?xml version="1.0" encoding="utf-8"?>
<OperatorStationCollection xmlns="http://www.w3.org" >
<OperatorStation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Name>OS001</Name>
    <Nodes>
      <DataNodeBase xsi:type="Adaptor">
        <Family>NetworkSettings</Family>
        <Name>Network A</Name>  
        <IPAddress>111.11.11.1</IPAddress>        
      </DataNodeBase>
      <DataNodeBase xsi:type="Adaptor">
        <Family>Network1111</Family>
        <Name>Network B</Name>                
        <IPAddress>111.22.11.1</IPAddress>          
      </DataNodeBase>
      <DataNodeBase xsi:type="Adaptor">
        <Family>Network2222</Family>
        <Name>Network C</Name>
        <IPAddress>111.33.11.1</IPAddress>
      </DataNodeBase>
      </Nodes>   
  </OperatorStation>      
<OperatorStation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Name>OS002</Name>
  <Nodes>
    <DataNodeBase xsi:type="Adaptor">
      <Family>NetworkSettings</Family>
      <Name>Network A</Name>
      <IPAddress>111.11.11.1</IPAddress>
    </DataNodeBase>
    <DataNodeBase xsi:type="Adaptor">
      <Family>Network1111</Family>
      <Name>Network B</Name>
      <IPAddress>111.22.11.2</IPAddress>
    </DataNodeBase>
    <DataNodeBase xsi:type="Adaptor">
      <Family>NetworkSettings</Family>
      <Name>Network D</Name>
      <IPAddress>111.33.11.2</IPAddress>
    </DataNodeBase>
  </Nodes>
</OperatorStation>
  <OperatorStation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Name>OS003</Name>
    <Nodes>
      <DataNodeBase xsi:type="Adaptor">
        <Family>NetworkSettings</Family>
        <Name>Network A</Name>
        <IPAddress>111.11.11.1</IPAddress>
      </DataNodeBase>
      <DataNodeBase xsi:type="Adaptor">
        <Family>NetworkSettings</Family>
        <Name>Network B</Name>
        <IPAddress>111.22.11.3</IPAddress>
      </DataNodeBase>
      <DataNodeBase xsi:type="Adaptor">
        <Family>NetworkSettings</Family>
        <Name>Network E</Name>
        <IPAddress>111.33.11.3</IPAddress>
      </DataNodeBase>
    </Nodes>
  </OperatorStation>
</OperatorStationCollection>

XSLT code for version 2.0:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
      <xsl:template match="/">
        <xsl:variable name="allStations"
                      select="/*:OperatorStationCollection/*:OperatorStation" />
        <table>
          <!-- Header row - two fixed columns plus one per station name -->
          <tr>
            <td>Name</td><td>Status</td>
            <xsl:for-each select="$allStations">
              <td><xsl:value-of select="*:Name" /></td>
            </xsl:for-each>
          </tr>
          <!-- main rows - one per "group" of DataNodeBase elements which share the
               same Name -->
          <xsl:for-each-group
              select="$allStations/*:Nodes/*:DataNodeBase"
              group-by="*:Name">
            <!-- calculate the column values - the IPAddress if this network (i.e. the
                 current-group) has an entry for this station, and "None" if not -->
            <xsl:variable name="addresses"
                select="for $s in ($allStations)
                        return (current-group()[../.. is $s]/*:IPAddress, 'None')[1]" />
            <tr>
              <td><xsl:value-of select="current-grouping-key()" /></td>
              <td>
                <!-- equal if all the $addresses are the same, unequal otherwise -->
                <xsl:value-of select="if (count(distinct-values($addresses)) = 1)
                                      then 'Equal' else 'Unequal'" />
              </td>
              <xsl:for-each select="$addresses">
                <td><xsl:value-of select="."/></td>
              </xsl:for-each>
            </tr>
          </xsl:for-each-group>
        </table>
      </xsl:template>
    </xsl:stylesheet> 

Expected OUTPUT: As there is no provision to add table , I have made hatml code for result, please save this code to html file and see expected output.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>    
</head>
<body>

   <table>
            <tr>
            <td>Name</td><td>Status</td><td>OS01</td><td>OS02</td><td>OS03</td>
            </tr>
            <tr>
            <td>Network A</td><td>Equal</td><td>111.11.11.1</td><td>111.11.11.1</td><td>111.11.11.1</td>
            </tr>
            <tr>
            <td>Network B</td><td>Unequal</td><td>111.22.11.1</td><td>111.22.11.2</td><td>111.22.11.2</td>
            </tr>
            <tr>
            <td>Network C</td><td>Unequal</td><td>111.33.11.1</td><td>Not Exist</td><td>Not Exist</td>
            </tr>
            <tr>
            <td>Network D</td><td>Unequal</td><td>Not Exist</td><td>111.33.11.2</td><td>Not Exist</td>
            </tr>
            <tr>
            <td>Network E</td><td>Unequal</td><td>Not Exist</td><td>Not Exist</td><td>111.33.11.3</td>
            </tr>           
            </table>

</body>
</html>

In the previous question it is mentioned about Muenchian Grouping, so you must be already aware this is the approach to take. In this case, you are grouping by the network name, which will form the basis of your table rows, so you define a key like this

<xsl:key name="networks" match="w3:DataNodeBase" use="w3:Name"/>

(The w3: prefix is used here because of namespaces. All your nodes in your XML are in the namespace " http://www.w3.org " and in XSLT 1.0 you will need to explicitly declare this)

Also, you will need to check for distinct value of IP Address for each network later, so it is also worth defining a key to help doing this

<xsl:key name="networksAndIP" match="w3:DataNodeBase" use="concat(w3:Name, '|', w3:IPAddress)"/>

Note the | symbol here. It can be any character you choose, just as long as it doesn't occur in either Name or IPAddress )

For getting the columns, which are your OperatorStation elements, the code is very much as before (with the main difference being about the namespace prefix)

<xsl:variable name="allStations" select="//w3:OperatorStation"/>

Outputting the columns is then much as before too

        <xsl:for-each select="$allStations">
           <td>
              <xsl:value-of select="w3:Name"/>
           </td>
        </xsl:for-each>

The first main difference though is when you want to get the distinct networks, for your columns. This is where you use Muenchian Grouping

<xsl:apply-templates 
     select="//w3:DataNodeBase
              [generate-id() = generate-id(key('networks', w3:Name)[1])]" />

Within the template that matches this, you can check for whether all IP addresses are the same by using the second key

<xsl:choose>
    <xsl:when test="count(key('networksAndIP', concat(w3:Name, '|', w3:IPAddress))) = $allStationsCount">Equal</xsl:when>
    <xsl:otherwise>Unequal</xsl:otherwise>
</xsl:choose>

Outputing the IP addresses for the row, is then simply a case of looping over the stations, and outputting the one with the matching network

<xsl:variable name="network" select="w3:Name"/>
<xsl:for-each select="$allStations">
   <td>
      <xsl:value-of select="key('networks', $network)[../../w3:Name=current()/w3:Name]/w3:IPAddress"/>
   </td>
</xsl:for-each>

Note that the following expression would also work in this case

<xsl:value-of select="w3:Nodes/w3:DataNodeBase[w3:Name=$network]/w3:IPAddress"/>

Anyway, try this XSLT

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

   <xsl:key name="networks" match="w3:DataNodeBase" use="w3:Name"/>
   <xsl:key name="networksAndIP" match="w3:DataNodeBase" use="concat(w3:Name, '|', w3:IPAddress)"/>

   <xsl:variable name="allStations" select="//w3:OperatorStation"/>
   <xsl:variable name="allStationsCount" select="count($allStations)"/>

   <xsl:template match="/">
      <table><!-- Header row - two fixed columns plus one per station name -->
         <tr>
            <td>Name</td>
            <td>Status</td>
            <xsl:for-each select="$allStations">
               <td>
                  <xsl:value-of select="w3:Name"/>
               </td>
            </xsl:for-each>
         </tr>
         <xsl:apply-templates select="//w3:DataNodeBase[generate-id() = generate-id(key('networks', w3:Name)[1])]"/>
      </table>
   </xsl:template>

   <xsl:template match="w3:DataNodeBase">
      <tr>
         <td>
            <xsl:value-of select="w3:Name"/>
         </td>
         <td>
            <xsl:choose>
               <xsl:when test="count(key('networksAndIP', concat(w3:Name, '|', w3:IPAddress))) = $allStationsCount">Equal</xsl:when>
               <xsl:otherwise>Unequal</xsl:otherwise>
            </xsl:choose>
         </td>
         <xsl:variable name="network" select="w3:Name"/>
         <xsl:for-each select="$allStations">
            <td>
               <xsl:value-of select="key('networks', $network)[../../w3:Name=current()/w3:Name]/w3:IPAddress"/>
            </td>
         </xsl:for-each>
      </tr>
   </xsl:template>
</xsl:stylesheet>

EDIT: If you wish to restrict the entries to a certain family, in this case just add a condition to check the family to the two keys

<xsl:key name="networks" match="w3:DataNodeBase[w3:Family='NetworkSettings']" use="w3:Name"/>
<xsl:key name="networksAndIP" match="w3:DataNodeBase[w3:Family='NetworkSettings']" use="concat(w3:Name, '|', w3:IPAddress)"/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM