如何比较两个XML节点并使用XSLT获得比较结果?

时间:2014-01-03 10:06:50

标签: xslt

XML文件作为输入和预期输出如下所示。可以参考链接...
XSLT node value comparision

我正在寻找xml中的输出,但如果有人制作xslt文件,以表格格式给出/显示结果,那就太棒了。

说明:XML文件包含运营商节点的集合,每个运营商站都有多个网络,现在从每个运营商的每个节点收集IP地址,并显示其值并与每个运营商站点进行比较,如下所示。如果每个运营商网络IP相等,则它显示状态为Equal否则不相等。应使用IPAddress进行比较,并参考Family和Name。比较OS01的IPAddress与具有相同系列(NetworkSettings)和Name(网络A)的其他操作系统。

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>KM-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>NetworkSettings</Family>
        <Name>Network B</Name>                
        <IPAddress>111.22.11.1</IPAddress>          
      </DataNodeBase>
      <DataNodeBase xsi:type="Adaptor">
        <Family>NetworkSettings</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>KM-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>NetworkSettings</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>KM-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的预期输出: 这里没有添加表的选项,所以请考虑&lt;&gt;作为用于设计表格的分隔符,&lt;&gt;不是结果的一部分,它只是添加到单独的列值。请在表格中考虑以下结果。

标题名称&lt;&gt;状态&lt;&gt; OS01&lt;&gt; OS02&lt;&gt; OS03

网络A&lt;&gt;等于&lt;&gt; 111.11.11.1&lt;&gt; 111.11.11.1&lt;&gt; 111.11.11.1

网络B&lt;&gt;不等&lt;&gt; 111.22.11.1&lt;&gt; 111.22.11.2&lt;&gt; 111.22.11.2

网络C&lt;&gt;不等&lt;&gt; 111.33.11.1&lt;&gt;不存在&lt;&gt;不存在

网络D&lt;&gt;不等&lt;&gt;不存在&lt;&gt; 111.33.11.2&lt;&gt;不存在

网络E&lt;&gt;不等&lt;&gt;不存在&lt;&gt;不存在&lt;&gt; 111.33.11.3

以下代码以表格格式显示预期结果。 保存下面的代码fileName.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>

1 个答案:

答案 0 :(得分:1)

因此,您希望每个操作员站名称有一列,每个不同网络名称需要一行。在XSLT 2.0中,可以使用for-each-group

很好地完成此操作
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    xmlns:w3="http://www.w3.org" exclude-result-prefixes="w3">
  <xsl:template match="/">
    <xsl:variable name="allStations"
                  select="/w3:OperatorStationCollection/w3: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="w3: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/w3:Nodes/w3:DataNodeBase"
          group-by="w3: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]/w3: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>

如果你被限制在1.0那么逻辑是相同的但是样式表更加冗长 - 你将不得不使用“Muenchian分组”方法来替换for-each-group,以及相等/不等的计算有点麻烦,因为你没有distinct-values函数或定义任意值序列的能力(2.0版本中的$addresses变量):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
     xmlns:w3="http://www.w3.org" exclude-result-prefixes="w3">

  <!-- grouping key to pull out all the DataNodeBase elements with a
       particular name -->
  <xsl:key name="dnbByName" match="w3:DataNodeBase" use="w3:Name" />

  <xsl:template match="/">
    <xsl:variable name="allStations"
                  select="/w3:OperatorStationCollection/w3:OperatorStation" />
    <table>
      <tr>
        <td>Name</td><td>Status</td>
        <xsl:for-each select="$allStations">
          <td><xsl:value-of select="w3:Name" /></td>
        </xsl:for-each>
      </tr>
      <!-- Muenchian grouping - for-each over a set consisting of just one
           DataNodeBase per network name "group" -->
      <xsl:for-each select="$allStations/w3:Nodes/w3:DataNodeBase[
            generate-id() = generate-id(key('dnbByName', w3:Name)[1])]">
        <xsl:variable name="current-group" select="key('dnbByName', w3:Name)" />
        <xsl:variable name="current-grouping-key" select="w3:Name" />
        <tr>
          <td><xsl:value-of select="$current-grouping-key" /></td>
          <td>
            <xsl:choose>
              <!-- "Equal" if all stations have a value for this network name,
                   and all these values are the same (it is not the case that
                   any of the values is different from that of the first
                   station) -->
              <xsl:when test="count($current-group) = count($allStations)
                  and not($current-group/w3:IPAddress
                          != $current-group[1]/w3:IPAddress)">
                <xsl:text>Equal</xsl:text>
              </xsl:when>
              <xsl:otherwise>
                <xsl:text>Unequal</xsl:text>
              </xsl:otherwise>
            </xsl:choose>
          </td>
          <!-- remaining columns, one per station -->
          <xsl:for-each select="$allStations">
            <td>
              <!-- check whether this station has an address for this network -->
              <xsl:variable name="address" select="w3:Nodes/w3:DataNodeBase[
                      w3:Name = $current-grouping-key]/w3:IPAddress" />
              <xsl:choose>
                <xsl:when test="$address">
                  <xsl:value-of select="$address" />
                </xsl:when>
                <xsl:otherwise>None</xsl:otherwise>
              </xsl:choose>
            </td>
          </xsl:for-each>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>
</xsl:stylesheet>