将 XSLT 代码从 2.0 版转换为 1.0 版 [英] convert XSLT code from version 2.0 to 1.0

查看:25
本文介绍了将 XSLT 代码从 2.0 版转换为 1.0 版的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有 2.0 版的 xslt 代码,它提供如下所示的输出,但我想将其转换为 1.0 版.我提到了以下链接..如何比较两个 XML 节点并得到使用 XSLT 比较结果?xslt 比较两个不同的节点然后组合

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

输入 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>

2.0 版的 XSLT 代码:

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> 

预期输出:由于没有提供添加表格,我已经为结果制作了 hatml 代码,请将此代码保存到 html 文件并查看预期输出.

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>

推荐答案

在上一个问题中提到了 Muenchian Grouping,因此您必须已经意识到这是要采取的方法.在这种情况下,您将按网络名称分组,这将构成表格行的基础,因此您可以像这样定义一个键

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"/>

(这里使用 w3: 前缀是因为命名空间.XML 中的所有节点都在命名空间 "http://www.w3.org" 并且在 XSLT 1.0 中,您需要明确声明这一点)

(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)

此外,稍后您将需要检查每个网络的 IP 地址的不同值,因此也值得定义一个密钥来帮助执行此操作

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)"/>

注意这里的 | 符号.它可以是您选择的任何字符,只要它不出现在 NameIPAddress)

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

为了获取列,即您的 OperatorStation 元素,代码与以前非常相似(主要区别在于命名空间前缀)

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"/>

输出列也和以前一样

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

不过,第一个主要区别是您何时想要为您的列获取不同的网络.这是您使用 Muenchian Grouping 的地方

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])]" />

在与此匹配的模板中,您可以使用第二个键检查所有IP地址是否相同

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>

输出行的IP地址,然后简单地循环站点,并输出具有匹配网络的站点

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"/>

无论如何,试试这个 XSLT

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>

如果您希望将条目限制为某个系列,在这种情况下,只需添加一个条件来检查两个键的系列

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)"/>

这篇关于将 XSLT 代码从 2.0 版转换为 1.0 版的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆