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



下面的 XSLT 代码通过父节点比较结果为我提供了结果。我正在寻找子节点比较结果,预期结果如下所示。描述:XSLT 代码给出了父节点(网络 A、网络 B 等),我想要子节点(网络 AA、网络 AB 等)比较结果。我建议您检查输入xml文件和预期的输出,以轻松理解我的要求。请参考链接将XSLT代码从2.0版转换为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>

在回答之前,我假设您错过了 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>

最新更新