Хобрук: Ваш путь к мастерству в программировании

xslt: сортировка, сравнение и возврат значений

Итак, я работаю с xml хоккейной статистики, которая генерируется отдельной программой. In создает узел для каждого игрока с подузлами для каждого сезона (плюс один для общего количества карьеры), с подузлами в каждом сезоне для типа статистики, а затем со значениями в этих подузлах.

Образец XML:

  <player name="Player A" checkname="A,PLAYER">
      <stats year="2017-18" gp="30">
        <shots g="3" a="1" pts="4" sh="23" pct=".130" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="0" sh="0" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="0" minutes="0" minor="0" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="10" minus="9" plusminus="+1" facewon="67" facelost="71" facepct=".486" blk="17"></misc>
      </stats>
      <stats year="2018-19" gp="37">
        <shots g="5" a="5" pts="10" sh="28" pct=".179" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="0" sh="1" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="2" minutes="4" minor="2" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="15" minus="13" plusminus="+2" facewon="118" facelost="106" facepct=".527" blk="23"></misc>
      </stats>
      <stats year="2019-20" gp="3">
        <shots g="2" a="0" pts="2" sh="6" pct=".333" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="1" sh="0" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="0" minutes="0" minor="0" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="1" minus="2" plusminus="-1" facewon="36" facelost="30" facepct=".545" blk="3"></misc>
      </stats>
      <stats year="TOTAL" gp="70">
        <shots g="10" a="6" pts="16" sh="57" pct=".175" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="1" sh="1" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="2" minutes="4" minor="2" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="26" minus="24" plusminus="+2" facewon="221" facelost="207" facepct=".516" blk="43"></misc>
      </stats>

  </player>

  <player name="Player B" checkname="B,PLAYER">
      <stats year="2016-17" gp="37">
        <shots g="1" a="11" pts="12" sh="24" pct=".042" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="0" sh="0" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="7" minutes="14" minor="7" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="33" minus="26" plusminus="+7" facewon="1" facelost="0" facepct="1.000" blk="54"></misc>
      </stats>
      <stats year="2017-18" gp="36">
        <shots g="3" a="14" pts="17" sh="47" pct=".064" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="1" sh="0" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="8" minutes="16" minor="8" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="31" minus="34" plusminus="-3" facewon="0" facelost="1" facepct=".000" blk="43"></misc>
      </stats>
      <stats year="2018-19" gp="37">
        <shots g="3" a="13" pts="16" sh="44" pct=".068" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="0" sh="0" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="5" minutes="10" minor="5" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="40" minus="36" plusminus="+4" facewon="1" facelost="0" facepct="1.000" blk="47"></misc>
      </stats>
      <stats year="2019-20" gp="3">
        <shots g="0" a="0" pts="0" sh="2" pct=".000" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="0" sh="0" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="2" minutes="4" minor="2" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="1" minus="4" plusminus="-3" facewon="0" facelost="0" facepct=".000" blk="4"></misc>
      </stats>
      <stats year="TOTAL" gp="113">
        <shots g="7" a="38" pts="45" sh="117" pct=".060" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="1" sh="0" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="22" minutes="44" minor="22" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="105" minus="100" plusminus="+5" facewon="2" facelost="1" facepct=".667" blk="148"></misc>
      </stats>

  </player>

  <player name="Player C" checkname="C,PLAYER">
      <stats year="2017-18" gp="25">
        <shots g="1" a="3" pts="4" sh="25" pct=".040" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="0" sh="0" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="4" minutes="19" minor="2" major="1" misc10="0" miscgame="1" miscgross="0" match="0"></penalty>
        <misc plus="2" minus="8" plusminus="-6" facewon="1" facelost="5" facepct=".167" blk="14"></misc>
      </stats>
      <stats year="2018-19" gp="33">
        <shots g="3" a="2" pts="5" sh="47" pct=".064" ps="0" psatt="0"></shots>
        <goaltype gw="1" pp="0" sh="0" ua="1" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="7" minutes="14" minor="7" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="5" minus="11" plusminus="-6" facewon="3" facelost="5" facepct=".375" blk="25"></misc>
      </stats>
      <stats year="2019-20" gp="3">
        <shots g="0" a="1" pts="1" sh="3" pct=".000" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="0" sh="0" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="1" minutes="2" minor="1" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="1" minus="3" plusminus="-2" facewon="0" facelost="3" facepct=".000" blk="4"></misc>
      </stats>
      <stats year="TOTAL" gp="61">
        <shots g="4" a="6" pts="10" sh="75" pct=".053" ps="0" psatt="0"></shots>
        <goaltype gw="1" pp="0" sh="0" ua="1" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="12" minutes="35" minor="10" major="1" misc10="0" miscgame="1" miscgross="0" match="0"></penalty>
        <misc plus="8" minus="22" plusminus="-14" facewon="4" facelost="13" facepct=".235" blk="43"></misc>
      </stats>

  </player>

  <player name="Player D" checkname="D,PLAYER">
      <stats year="2018-19" gp="29">
        <shots g="1" a="9" pts="10" sh="33" pct=".030" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="1" sh="0" ua="0" fg="1" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="2" minutes="4" minor="2" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="12" minus="12" plusminus="0" facewon="116" facelost="94" facepct=".552" blk="8"></misc>
      </stats>
      <stats year="2019-20" gp="3">
        <shots g="0" a="0" pts="0" sh="2" pct=".000" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="0" sh="0" ua="0" fg="0" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="1" minutes="2" minor="1" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="0" minus="2" plusminus="-2" facewon="22" facelost="24" facepct=".478" blk="2"></misc>
      </stats>
      <stats year="TOTAL" gp="32">
        <shots g="1" a="9" pts="10" sh="35" pct=".029" ps="0" psatt="0"></shots>
        <goaltype gw="0" pp="1" sh="0" ua="0" fg="1" ot="0" en="0" hat="0" gt="0" so="0"></goaltype>
        <penalty count="3" minutes="6" minor="3" major="0" misc10="0" miscgame="0" miscgross="0" match="0"></penalty>
        <misc plus="12" minus="14" plusminus="-2" facewon="138" facelost="118" facepct=".539" blk="10"></misc>
      </stats>

  </player>

То, что я пытаюсь сделать, это иметь файл xslt, вернуть значение и имя лучшего игрока (ов) для указанной категории статистики для данного сезона. Например, начиная с очков (@pts).

Мне удалось заставить его вернуть лучший результат и игрока, используя некоторую базовую сортировку, однако я хочу добавить больше логики в ситуациях, когда есть ничья для вершины.

Вот что у меня есть для поиска лидера по количеству очков:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0" exclude-result-prefixes="msxsl">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/">
        <STATS>
            <season_leaders>
                <xsl:for-each select="player/stats[@year='2019-20']">
                    <xsl:sort select="shots/@pts"  data-type="number" order="descending"/>
                    <xsl:if test="(position() = 1)">
                        <points>
                            <xsl:value-of select="shots/@pts"/> - <xsl:value-of select="../@name"/>
                        </points>
                    </xsl:if>
                </xsl:for-each>
            </season_leaders>
        </STATS>
    </xsl:template>
</xsl:stylesheet>

Просто текстовый возврат начального значения и имени лидера, разделенных тире, - это именно то, что я хочу. Однако я хотел бы, чтобы он сравнивал три верхних значения, а в случае связи двух человек возвращал единственное верхнее значение и фамилии двух связанных людей. А в случае ничьей из трех или более человек верните верхнее значение с текстом, говорящим о множественных связях.

Я пробовал использовать функцию position() при вызове значения, но она, похоже, не работает, т.е. <xsl:value-of select="shots[position()=1]/@pts"/> и другие варианты.

Любая помощь в том, как я могу заставить его сравнивать верхние отсортированные значения и возвращать разные результаты на основе результатов этого сравнения? Наконец, я считаю, что это, к сожалению, должно быть сделано в XSLT версии 1.0.

02.12.2020

  • Показанный вами ввод не является правильно сформированным XML (без единого корневого элемента). 03.12.2020

Ответы:


1

Попробуйте что-то вроде:

XSLT 1.0

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

<xsl:param name="year" select="'2019-20'"/>
<xsl:key name="stats" match="stats" use="concat(@year, '|', shots/@pts)" />

<xsl:template match="/players">
    <STATS>
        <season_leaders>
            <xsl:variable name="max">
                <xsl:for-each select="player/stats[@year=$year]/shots">
                    <xsl:sort select="@pts" data-type="number" order="descending"/>
                    <xsl:if test="(position()=1)">
                        <xsl:value-of select="@pts"/>
                    </xsl:if>
                </xsl:for-each>
            </xsl:variable>
            <xsl:variable name="leaders" select="key('stats', concat($year, '|', $max))" />
            <points>
                <xsl:value-of select="$max"/>
                <xsl:text> - </xsl:text>
                <xsl:choose>
                    <xsl:when test="count($leaders) > 2">multiple tied.</xsl:when>
                    <xsl:otherwise>
                        <xsl:for-each select="$leaders">
                            <xsl:value-of select="../@name"/>
                            <xsl:if test="position()!=last()">, </xsl:if>
                        </xsl:for-each>
                    </xsl:otherwise>
                </xsl:choose>
            </points>
        </season_leaders>
    </STATS>
</xsl:template>

</xsl:stylesheet>

Демонстрация (с использованием правильного XML в качестве входных данных: http://xsltfiddle.liberty-development.net/gVrvcxm

02.12.2020
  • Извините, корень очень простой: ` ‹hkcareer source=TAS For Ice Hockey version=1.1.0 date=12 октября 2019› ‹код команды= name=›‹/team› ‹имя игрока=Player A и т. д. и т. д. и т.д... ‹/player› ‹/hkcareer› ` hkcareer — это корневой узел, и он был у меня в моем xslt, но я убрал его из своего примера, так как его не было в примере xml-чанка. 03.12.2020
  • Большое спасибо за помощь. Я думаю, что это будет работать отлично! 03.12.2020
  • Дополнительный вопрос. Есть ли способ добавить проверку, чтобы игроки должны были иметь определенный минимум от общей суммы команды, чтобы претендовать на звание лидера. Например, misc/facepct — это процент побед и поражений, однако, если кто-то только 1-к-1, он будет лидером с 1,00, но это не отражает истинного лидера, у которого может быть более 100 очков (выиграно + проиграно). . Есть ли способ суммировать все выигранные и проигранные лица за данный год, а затем проверить, есть ли у лидера определенный % минимум от общего количества, а если нет, то он пропущен к следующему лидеру и так далее? 03.12.2020
  • Пожалуйста, не задавайте вопросы в комментариях. При необходимости опубликуйте новый вопрос с вашим новым требованием. Звучит как серьезное осложнение, но я не уверен, что полностью его понимаю. 03.12.2020
  • Новые материалы

    ВЫ РЕГРЕСС ЭТО?
    Чтобы понять, когда использовать регрессионный анализ, мы должны сначала понять, что именно он делает. Вот простой ответ, который появляется, когда вы используете Google: Регрессионный..

    Не зря же это называют интеллектом
    Стек — C#, Oracle Опыт — 4 года Работа — Разведывательный корпус Мне пора служить Может быть, я немного приукрашиваю себя, но там, где я живу, есть обязательная военная служба на 3..

    LeetCode Проблема 41. Первый пропущенный положительный результат
    LeetCode Проблема 41. Первый пропущенный положительный результат Учитывая несортированный массив целых чисел, найдите наименьшее пропущенное положительное целое число. Пример 1: Input:..

    Расистский и сексистский робот, обученный в Интернете
    Его ИИ основан на предвзятых данных, которые создают предрассудки. Он словно переходит из одного эпизода в другой из серии Черное зеркало , а вместо этого представляет собой хронику..

    Управление состоянием в микрофронтендах
    Стратегии бесперебойного сотрудничества Микро-фронтенды — это быстро растущая тенденция в сфере фронтенда, гарантирующая, что удовольствие не ограничивается исключительно бэкэнд-системами..

    Декларативное и функциональное программирование в стиле LINQ с использованием JavaScript с использованием каррирования и генератора ...
    LINQ - одна из лучших функций C #, которая обеспечивает элегантный способ написания кода декларативного и функционального стиля, который легко читать и понимать. Благодаря таким функциям ES6,..

    Структуры данных в C ++ - Часть 1
    Реализация общих структур данных в C ++ C ++ - это расширение языка программирования C, которое поддерживает создание классов, поэтому оно известно как C с классами . Он используется для..