如何获取子节点结果而不是父节点?

时间:2014-01-05 12:56:57

标签: xslt

下面的XSLT代码给出了父节点比较结果的结果。我正在寻找子节点比较结果,预期结果如下所示。 描述:XSLT代码给出了父节点(网络A,网络B等),我希望子节点(网络AA,网络AB等)比较结果。我建议你检查输入xml文件和预期输出,以便轻松了解我的要求。请参考链接convert XSLT code from version 2.0 to 1.0

输入XML文件:

    <?xml version="1.0" encoding="utf-8"?>
<OperatorStationCollection >
  <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>
        <ChildNodes>
            <DataNodeChild xsi:type="SubResult">
                <Family>NetworkSettings</Family>
                <Name>Network AA</Name>
                <IPAddress>111.11.11.12</IPAddress>
            </DataNodeChild>
            <DataNodeChild xsi:type="SubResult">
                <Family>NetworkSettings</Family>
                <Name>Network AB</Name>
                <IPAddress>111.11.11.13</IPAddress>
            </DataNodeChild>            
        </ChildNodes>
      </DataNodeBase>
      <DataNodeBase xsi:type="Adaptor">
        <Family>NetworkSettings</Family>
        <Name>Network B</Name>
        <IPAddress>111.22.11.1</IPAddress>
        <ChildNodes>
            <DataNodeChild xsi:type="SubResult">
                <Family>NetworkSettings</Family>
                <Name>Network BA</Name>
                <IPAddress>111.11.11.21</IPAddress>
            </DataNodeChild>
            <DataNodeChild xsi:type="SubResult">
                <Family>NetworkSettings</Family>
                <Name>Network BB</Name>
                <IPAddress>111.11.11.31</IPAddress>
            </DataNodeChild>            
        </ChildNodes>
      </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>
        <ChildNodes>
            <DataNodeChild xsi:type="SubResult">
                <Family>NetworkSettings</Family>
                <Name>Network AA</Name>
                <IPAddress>111.11.11.12</IPAddress>
            </DataNodeChild>
            <DataNodeChild xsi:type="SubResult">
                <Family>NetworkSettings</Family>
                <Name>Network AB</Name>
                <IPAddress>111.11.11.13</IPAddress>
            </DataNodeChild>            
        </ChildNodes>
      </DataNodeBase>
      <DataNodeBase xsi:type="Adaptor">
        <Family>NetworkSettings</Family>
        <Name>Network B</Name>
        <IPAddress>111.22.11.1</IPAddress>
        <ChildNodes>
            <DataNodeChild xsi:type="SubResult">
                <Family>NetworkSettings</Family>
                <Name>Network BA</Name>
                <IPAddress>111.11.11.12</IPAddress>
            </DataNodeChild>
            <DataNodeChild xsi:type="SubResult">
                <Family>NetworkSettings</Family>
                <Name>Network BB</Name>
                <IPAddress>111.11.11.13</IPAddress>
            </DataNodeChild>            
        </ChildNodes>
      </DataNodeBase>      
    </Nodes>
  </OperatorStation>
</OperatorStationCollection>

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>

预期输出:由于没有添加表的规定,我已经为结果制作了hatml代码,请将此代码保存到html文件并查看预期输出。为了理解我已经制作了表格,我正在寻找xml中的输出但是如果有人制作xslt文件以表格格式给出/显示结果会很棒。

<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>
            </tr>
            <tr>
            <td>Network AB</td><td>Equal</td><td>111.11.11.12</td><td>111.11.11.12</td>
            </tr>
            <tr>
            <td>Network AB</td><td>Equal</td><td>111.11.11.13</td><td>111.11.11.13</td>
            </tr>
            <tr>
            <td>Network BA</td><td>Unequal</td><td>111.11.11.21</td><td>111.11.11.12</td>
            </tr>
            <tr>
            <td>Network BB</td><td>Unequal</td><td>111.11.11.31</td><td>111.11.11.13</td>
            </tr>                   
            </table>

</body>
</html>

1 个答案:

答案 0 :(得分:0)

在回答之前,我假设您错过了XML中的命名空间声明,并且根元素应该看起来像这样(如果没有,您还需要从XSLT中删除所有命名空间的跟踪)

<OperatorStationCollection xmlns="http://www.w3.org">

在上一个问题中,您是按 DataNodeBase 进行分组,但在新问题中,您要按 DataNodeChild 进行分组。这意味着您真正需要做的就是在XSLT中用 DataNodeChild 替换所有出现的 DataNodeBase

唯一的另一个变化就是这一行

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

因为 DataNodeChild 嵌套了两个更高级别,所以必须相应地更改表达式

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

更好的是,要在任何级别应对它,可能就是这个

<xsl:value-of 
     select="key('networks', $network)[ancestor::w3:OperatorStation/w3:Name=current()/w3:Name]/w3:IPAddress"/>

就是这样。试试这个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:DataNodeChild" use="w3:Name"/>
   <xsl:key name="networksAndIP" match="w3:DataNodeChild" 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:DataNodeChild[generate-id() = generate-id(key('networks', w3:Name)[1])]"/>
      </table>
   </xsl:template>
   <xsl:template match="w3:DataNodeChild">
      <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)[ancestor::w3:OperatorStation/w3:Name=current()/w3:Name]/w3:IPAddress"/>
            </td>
         </xsl:for-each>
      </tr>
   </xsl:template>
</xsl:stylesheet>