【问题标题】:XSLT determine which attribute is repeated the mostXSLT 确定哪个属性重复次数最多
【发布时间】:2013-09-06 00:15:41
【问题描述】:

我正在使用一些困难的标记,其中没有规范化的 ID。让我通过示例展示一下标记可能是什么样子:

<listing>
    <foo fooid="81">Foo</foo>
    <bar barid="88">Bar</bar>
</listing>
<listing>
    <foo fooid="82">Foo</foo>
    <bar barid="81">Bar</bar>
</listing>
<listing>
    <foo fooid="83">Foo</foo>
    <bar barid="81">Bar</bar>
</listing>

在这种情况下,我需要能够填充到&lt;xsl:variable /&gt; 中的 ID 是 81,因为无论其标签如何,该 id 被表示的次数最多。有没有一种简单的方法可以用 XSLT 做到这一点?理想情况下,当它说完后,我会有类似的东西:

&lt;xsl:variable name="an_id"&gt; 其中an_id 等于81

已知点如下:

  • 标签始终称为 foo 或 bar。
  • 属性始终称为 foid 或 barid
  • 我希望在变量中捕获的数字将在两个标签中的任何一个中至少列出一次
  • 我要捕获的数字肯定会在每个列表中至少出现一次。
  • 不相关的数字可能会出现多次,也可能不会出现。

我正在使用 XSLT 1.0。变量名不是动态的。是静态的,可以调用whatever,只要导出的值是上面的81即可。

** 更新 **

我在上面粘贴的 XML 是示例,虽然我认为 Mads 的答案是正确的,但它不会解析,所以我正在使用我正在处理的真实 XML 进行更新。您可以在我的人为示例中看到等价物,即 &lt;foo&gt;&lt;bar&gt; 正在尝试处理 &lt;hometeam&gt;&lt;awayteam&gt; 标签,这些是需要关注的关键标签。

<?xml version="1.0" standalone="no"?>
<message>
  <XML_File_ID>18996672</XML_File_ID>
  <heading>ABX%PHI-SKED</heading>
  <category>Statistics</category>
  <sport>NFL</sport>
  <title>2013 Philadelphia Eagles Schedule/Results</title>
  <season>2013</season>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4189</schedule_id>
    <Game_Date>09/09/2013</Game_Date>
    <Game_Time>06:55 PM</Game_Time>
    <week>1</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="081">Philadelphia</awayteam>
    <hometeam hometeamid="088">Washington</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>FedEx Field</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>ESPN</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4206</schedule_id>
    <Game_Date>09/15/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>2</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="083">San Diego</awayteam>
    <hometeam hometeamid="081">Philadelphia</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Lincoln Financial Field</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>CBS</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4253</schedule_id>
    <Game_Date>09/19/2013</Game_Date>
    <Game_Time>08:25 PM</Game_Time>
    <week>3</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="072">Kansas City</awayteam>
    <hometeam hometeamid="081">Philadelphia</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Lincoln Financial Field</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>NFL Network</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4331</schedule_id>
    <Game_Date>09/29/2013</Game_Date>
    <Game_Time>04:25 PM</Game_Time>
    <week>4</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="081">Philadelphia</awayteam>
    <hometeam hometeamid="067">Denver</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Sports Authority Field at Mile High Stadium</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4366</schedule_id>
    <Game_Date>10/06/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>5</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="081">Philadelphia</awayteam>
    <hometeam hometeamid="079">NY Giants</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>MetLife Stadium</Location>
    <Indoor>False</Indoor>
    <Turf>True</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4403</schedule_id>
    <Game_Date>10/13/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>6</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="081">Philadelphia</awayteam>
    <hometeam hometeamid="087">Tampa Bay</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Raymond James Stadium</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4419</schedule_id>
    <Game_Date>10/20/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>7</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="066">Dallas</awayteam>
    <hometeam hometeamid="081">Philadelphia</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Lincoln Financial Field</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4197</schedule_id>
    <Game_Date>10/27/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>8</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="079">NY Giants</awayteam>
    <hometeam hometeamid="081">Philadelphia</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Lincoln Financial Field</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4216</schedule_id>
    <Game_Date>11/03/2013</Game_Date>
    <Game_Time>04:05 PM</Game_Time>
    <week>9</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="081">Philadelphia</awayteam>
    <hometeam hometeamid="073">Oakland</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Oakland-Alameda County Coliseum</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4230</schedule_id>
    <Game_Date>11/10/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>10</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="081">Philadelphia</awayteam>
    <hometeam hometeamid="069">Green Bay</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Lambeau Field</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4251</schedule_id>
    <Game_Date>11/17/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>11</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="088">Washington</awayteam>
    <hometeam hometeamid="081">Philadelphia</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Lincoln Financial Field</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4302</schedule_id>
    <Game_Date>12/01/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>13</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="086">Arizona</awayteam>
    <hometeam hometeamid="081">Philadelphia</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Lincoln Financial Field</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4322</schedule_id>
    <Game_Date>12/08/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>14</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="068">Detroit</awayteam>
    <hometeam hometeamid="081">Philadelphia</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Lincoln Financial Field</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4350</schedule_id>
    <Game_Date>12/15/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>15</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="081">Philadelphia</awayteam>
    <hometeam hometeamid="076">Minnesota</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Mall of America Field at HHH Metrodome</Location>
    <Indoor>True</Indoor>
    <Turf>True</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4365</schedule_id>
    <Game_Date>12/22/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>16</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="063">Chicago</awayteam>
    <hometeam hometeamid="081">Philadelphia</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>Lincoln Financial Field</Location>
    <Indoor>False</Indoor>
    <Turf>False</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <listing>
    <season_type>Regular</season_type>
    <schedule_id>4391</schedule_id>
    <Game_Date>12/29/2013</Game_Date>
    <Game_Time>01:00 PM</Game_Time>
    <week>17</week>
    <ascore>0</ascore>
    <hscore>0</hscore>
    <awayteam awayteamid="081">Philadelphia</awayteam>
    <hometeam hometeamid="066">Dallas</hometeam>
    <TypeUpdate>P</TypeUpdate>
    <Status>
    </Status>
    <Location>AT&amp;T Stadium</Location>
    <Indoor>False</Indoor>
    <Turf>True</Turf>
    <TV_Listing>FOX</TV_Listing>
  </listing>
  <time_stamp> September 3, 2013, at 05:17 PM ET </time_stamp>
</message>

基本上,我正在尝试获取主队的 ID。由于在列表之前它没有在上面标准化,我必须选择每个列表中列出的团队(因此出现最多)。在本例中,Philadelphia 的 ID 为“081”,但是一旦在 XSLT 处理器中运行number(),它应该只是81

这是我目前根据 Mads 回答的样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" omit-xml-declaration="yes" />
  <xsl:strip-space elements="*" />

  <xsl:key name="id" match="@awayteamid | @hometeamid" use="."/>

  <xsl:template match="/message">
    <xsl:variable name="heading"><xsl:value-of select="heading"/></xsl:variable>
    <xsl:variable name="title"><xsl:value-of select="title"/></xsl:variable>
    <xsl:variable name="team_id">
      <xsl:for-each select="*/listing/*/@*">
         <xsl:sort select="count(key('id', .))" order="descending" data-type="number" />
         <xsl:if test="position()=1">
             <xsl:value-of select="."/>
         </xsl:if>
     </xsl:for-each>
   </xsl:variable>

    {
     "team_id": <xsl:value-of select="number($team_id)" /> 
    }
  </xsl:template>
</xsl:stylesheet>

最后是我使用它时遇到的错误(假设是因为 $team_id 没有正确设置)

#<JSON::ParserError: 203: unexpected token at 'NaN 
    }
  '>

【问题讨论】:

  • XSLT 1.0 还是 2.0?另请显示此示例输入的预期输出。请显示一个示例输入文档(不是您现在显示的非文档片段)。
  • 什么是 xslt 处理器?你想让变量名是动态的还是值?
  • 更新问题以解决 xslt 处理器和变量命名问题。
  • 不得不用实际数据再更新一次。认为 Mads 有正确的答案,但我无法让它与真实数据一起工作,这是我的错。
  • 您需要将 for-each 中的 XPath 调整为相对于上下文节点,即 message 元素:&lt;xsl:for-each select="listing/*/@*"&gt;

标签: xml xslt


【解决方案1】:

您可以定义与其中任一属性匹配的键:

<xsl:key name="id" match="@fooid | @barid" use="."/>

然后创建an_id变量,其值是属性值排序列表中的第一项,使用与属性值匹配的键中的项目数。

<xsl:variable name="an_id">
   <xsl:for-each select="*/listing/*/@*">
       <xsl:sort select="count(key('id', .))" order="descending" data-type="number"/>
       <xsl:if test="position()=1">
           <xsl:value-of select="."/>
       </xsl:if>
   </xsl:for-each>
</xsl:variable>

使用您的 XML 和 XSLT 更新了答案(您几乎已经有了,只需要调整 for-each 中的 XPath 以说明上下文节点是什么以及在评估表达式时您“站立”的位置):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" omit-xml-declaration="yes" />
    <xsl:strip-space elements="*" />

    <xsl:key name="id" match="@awayteamid | @hometeamid" use="."/>

    <xsl:template match="/message">
        <xsl:variable name="heading"><xsl:value-of select="heading"/></xsl:variable>
        <xsl:variable name="title"><xsl:value-of select="title"/></xsl:variable>
        <xsl:variable name="team_id">
            <xsl:for-each select="listing/*/@*">
                <xsl:sort select="count(key('id', .))" order="descending" data-type="number" />
                <xsl:if test="position()=1">
                    <xsl:value-of select="."/>
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>

        {
        "team_id": <xsl:value-of select="number($team_id)" /> 
        }
    </xsl:template>
</xsl:stylesheet>

【讨论】:

  • 这看起来是朝着正确的方向前进,但它始终拉出相同的 ID,这是错误的。它在文档中列出了两次,但另一个列出的频率更高。有什么调试建议吗?
  • ID 前面也填充了 0,这会有所不同吗?类似于“088”“077”等的东西。
  • @randombits:如果您认为它是错误的,请显示证明它错误的输入和输出。否则你的评论是没有用的。 Mad 的解决方案适用于您提供的示例数据。
  • 它们是一致的 3 位数字,还是 088、88、077、77 的混合?如果是混合物,那么会有所不同的是它们被视为字符串。
  • 真的很抱歉造成混乱。我发布了我正在处理的实际 XML。希望你能多看一眼。我认为通过浓缩它并组合一个人为的样本,它可以节省空间/时间。但实际上并没有,这是我的错。
【解决方案2】:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" />

<xsl:key name="kFoobars" match="foo/@fooid | bar/@fooid |
                                foo/@barid | bar/@barid" use="." />

<xsl:template match="/*">
  <xsl:variable name="foobar-els" select="*/foo | */bar" />
  <xsl:variable name="foobar-atr" select="$foobar-els/@fooid | $foobar-els/@barid" />
  <xsl:for-each select="$foobar-atr[ generate-id() =
                                     generate-id( key('kFoobars',.)[1])]">
    <xsl:sort select="count(key('kFoobars',.))" data-type="number" order="descending" />
    <xsl:if test="position()=1">
      <t most-populous-id-value="{.}" />
    </xsl:if>  
  </xsl:for-each>  
</xsl:template>

</xsl:stylesheet>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-03
    • 1970-01-01
    • 2021-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-05
    相关资源
    最近更新 更多