xslt сгруппировать по - php - PullRequest
       4

xslt сгруппировать по - php

0 голосов
/ 17 февраля 2012

Эй, у меня есть xollowing-файл foolowing:

<?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: выход должен быть таким:

Деп 010: 2 несчастных случая;dep 420: 1 несчастные случаи

спасибо, обратите внимание, я использую php, поэтому нельзя использовать saxon

Ответы [ 4 ]

0 голосов
/ 18 февраля 2012

Я должен признать, я не уверен, почему решения, использующие ключи, не работают для вас, но вот один, который не работает, который может работать в качестве обходного пути:

<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, считая себя и все последующие элементы accident с тем же dep. Он присваивает результат переменной, а затем с помощью подстроки отсекает конечный ;. Если это на самом деле не проблема, вы можете легко пропустить шаблон match="/".

0 голосов
/ 17 февраля 2012

Использование:

<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;
0 голосов
/ 17 февраля 2012

Это преобразование :

<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. мюнхенский метод группировки .

  2. Push-стиль обработки XSLT .

Обновление : OP не имеет настоящего XSLT-процессора - его инструмент не реализует xsl:key

В этом случае следующее решение (примечание - это гораздо менее эффективно, чемMuenchian grouping) все еще решает проблему, и производит точный требуемый вывод :

<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
0 голосов
/ 17 февраля 2012

Не уверен, почему вы хотели бы использовать XSLT для этого, но если вам нужно, вы можете легче создавать элементы dom из значений PHP:

$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" в качествеключ и номер аварии в качестве значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...