【问题标题】:xslt group by - phpxslt 分组 - php
【发布时间】:2012-02-17 02:14:41
【问题描述】:

嘿,我有一个愚蠢的 xml 文件:

<?xml version="1.0"?>
 <accidents>
 <accident>
  <org>1</org>
  <com>194</com>
  <dep>010</dep>
  <grav>0.64</grav>
 </accident>
 <accident>
  <org>1</org>
  <com>194</com>
  <dep>420</dep>
  <grav>0.54</grav>
 </accident>
 <accident>
  <org>1</org>
  <com>44</com>
  <dep>010</dep>
  <grav>0.4</grav>
 </accident>
</accidents>

我想应用一个 xslt 1.0 来计算 dep 的事故数量: 输出应该是这样的:

dep 010:2 起事故; dep 420 : 1 次事故

谢谢,注意我用的是php,所以不能用saxon

【问题讨论】:

    标签: php xml xslt grouping


    【解决方案1】:

    这种转变

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:key name="kAccByDept" match="accident" use="dep"/>
    
     <xsl:template match=
      "accident
        [generate-id()
        =
         generate-id(key('kAccByDept', dep)[1])
         ]">
         <xsl:if test="position() > 1"> ; </xsl:if>
    
         <xsl:value-of select=
          "concat('dep ', dep, ' : ',
                  count(key('kAccByDept', dep)), ' accidents')
          "/>
     </xsl:template>
     <xsl:template match="text()"/>
    </xsl:stylesheet>
    

    应用于提供的 XML 文档时

    <accidents>
        <accident>
            <org>1</org>
            <com>194</com>
            <dep>010</dep>
            <grav>0.64</grav>
        </accident>
        <accident>
            <org>1</org>
            <com>194</com>
            <dep>420</dep>
            <grav>0.54</grav>
        </accident>
        <accident>
            <org>1</org>
            <com>44</com>
            <dep>010</dep>
            <grav>0.4</grav>
        </accident>
    </accidents>
    

    产生想要的正确结果

    dep 010 : 2 accidents ; dep 420 : 1 accidents
    

    解释

    1. Muenchian method for grouping

    2. Push style of XSLT processing

    更新:OP 没有可用的真正 XSLT 处理器——他的工具没有实现 xsl:key

    在这种情况下,以下解决方案(注意——这比 Muenchian 分组效率低得多)仍然可以解决问题并产生确切的所需输出

    <xsl:stylesheet version="1.0"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
         <xsl:output method="text"/>
    
         <xsl:template match=
          "accident
            [not(dep
                =
                 preceding-sibling::*/dep
                 )
            ]
          ">
             <xsl:value-of select=
              "concat('dep ', dep, ' : ',
                      count(following-sibling::*[dep = current()/dep]) +1,
                      ' accidents')
              "/>
    
             <xsl:if test=
             "following-sibling::*/dep
                  [not(. = current()/dep)
                  and
                   not(.
                =
                 ../preceding-sibling::*/dep)
                  ]"> ; </xsl:if>
         </xsl:template>
         <xsl:template match="text()"/>
    </xsl:stylesheet>
    

    当应用于同一个 XML 文档(上图)时,会产生同样想要的正确结果:

    dep 010 : 2 accidents ; dep 420 : 1 accidents
    

    【讨论】:

    • 嘿,感谢您的回答,我在 Muenchian 分组方法之前尝试过,但没有奏效,我得到了与您的解决方案相同的错误:未实现键且未实现条形空间
    • @user986586:请参阅我更新的答案 - 该解决方案完全产生了想要的答案,与 Kirill 的解决方案不同。
    • @user986586:您提到您使用 PHP。 PHP(5) 的XSLTProcessor 是libxslt 的包装器。 libxslt 支持&lt;xsl:key/&gt;key()。也许你应该更新 libxslt 和/或 PHP。
    • 再次感谢您的回复,它正在工作,但我现在希望将输出作为 html 页面,如下所示
      420 010
      事故 1 2
    • @user986586:这是对需求的根本改变。您当前的问题已得到充分回答。请根据新要求提出一个新问题。请接受这个问题的最佳答案。
    【解决方案2】:

    不确定为什么要为此使用 XSLT,但如果必须,您可以更轻松地从 PHP 值创建 dom 元素:

    $dom = new DOMDocument;
    $dom->loadXML(file_get_contents('accidents.xml'));
    $xpath = new DOMXPath($dom);
    $deps = array();
    foreach ($xpath->query('/accidents/accident/dep') as $node) {
       $n = $node->nodeValue;
       if (!isset($deps[$n])) {
          $deps[$n] = 0;
       }
       $deps[$n]++;
    }
    

    这给出了一个以“dep”为键,事故编号为值的数组。

    【讨论】:

    • 感谢您的回答,但我需要使用 xsl 来尊重这个项目的架构
    • 你可以不使用任何PHP吗?这些值仍然可以通过 DOM 操作插入到 xsl 样式表中。
    • 不,我必须使用 xml 和 xsl 文件,并使用 jquery 插件将结果显示在 html 页面中
    【解决方案3】:

    用途:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="text"/>
      <xsl:key name="k" match="accident" use="dep"/>
    
      <xsl:template match="/accidents">
        <xsl:apply-templates select="accident[generate-id() = generate-id(key('k', dep))]"/>
      </xsl:template>
    
      <xsl:template match="accident">
        <xsl:value-of select="concat('dep ', dep, ' : ', count(key('k', dep)), ' accidents; ')"/>
      </xsl:template>
    </xsl:stylesheet>
    

    没有孟奇方法的解决方案:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="text"/>
    
      <xsl:template match="/accidents">
        <xsl:apply-templates select="accident[not(preceding-sibling::accident/dep = dep)]"/>
      </xsl:template>
    
      <xsl:template match="accident">
        <xsl:value-of select="concat('dep ', dep, ' : ', count(../accident[dep = current()/dep]), ' accidents; ')"/>
      </xsl:template>
    </xsl:stylesheet>
    

    输出:

    dep 010 : 2 accidents; dep 420 : 1 accidents;
    

    【讨论】:

      【解决方案4】:

      我不得不承认,我不确定为什么使用密钥的解决方案不适合您,但这里有一个不适合您的解决方案,这可能是一种解决方法:

      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>
      
        <xsl:template match="/">
          <xsl:variable name="list">
            <xsl:apply-templates />
          </xsl:variable>
          <xsl:value-of select="substring($list,1,string-length($list)-2)" />
        </xsl:template>
      
        <xsl:template match="accident">
          <xsl:if test="not(preceding-sibling::accident[dep = current()/dep])">
            <xsl:value-of select="concat('dep ',dep,' : ',count(. | following-sibling::accident[dep = current()/dep]),' accidents ;')" />
          </xsl:if>
        </xsl:template>
      </xsl:stylesheet>
      

      它仅在accident 元素之前没有具有相同dep 的同级元素时输出,计算它自己和所有具有相同depaccident 元素。它将结果分配给一个变量,然后使用子字符串切断尾随的;。如果这实际上不是问题,您可以轻松地完全忽略 match="/" 模板。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-20
        • 2021-12-21
        • 2018-05-26
        • 2014-03-19
        • 2013-11-09
        • 2010-12-26
        相关资源
        最近更新 更多