简体   繁体   English

将XSLT代码从2.0版转换为1.0版

[英]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. 有用于版本2.0的xslt代码,其输出如下所示,但我想将其转换为版本1.0。 I referred following links.. How to compare two XML nodes and get compared result using XSLT? 我引用了以下链接。 如何使用XSLT比较两个XML节点并获得比较结果? and xslt compare two different nodes and then combine xslt比较两个不同的节点,然后合并

Input XML file: 输入XML文件:

<?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: 版本2.0的XSLT代码:

<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. 预期的输出:由于没有提供添加表的准备,因此我为结果制作了hatml代码,请将此代码保存到html文件中,然后查看预期的输出。

<!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. 在前面的问题中提到了Muenchian分组,因此您必须已经意识到这是采取的方法。 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) (这里使用w3:前缀是因为存在名称空间。XML中的所有节点都在名称空间“ http://www.w3.org ”中,而在XSLT 1.0中,您需要明确声明这一点)

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 另外,您以后需要检查每个网络的IP地址的不同值,因此也有必要定义一个密钥来帮助完成此操作

<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 ) 它可以是您选择的任何字符,只要它不在NameIPAddress中出现就可以)

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) 为了获取作为OperatorStation元素的列,代码与以前非常相似(主要区别在于名称空间前缀)

<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 在这里使用Muenchian分组

<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 在与此匹配的模板中,您可以使用第二个键检查所有IP地址是否相同

<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 因此,输出该行的IP地址只是在工作站上循环,然后将其与匹配网络一起输出的情况

<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 无论如何,请尝试此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)"/>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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