XSLT xsl: сортировка не удалась с большими числами и data-type = "number" - PullRequest
1 голос
/ 24 января 2012

Я ненавижу даже спрашивать об этом, поскольку существует множество примеров, касающихся функциональности xsl: sort, однако я следовал им и до сих пор, по необъяснимым причинам, застрял.

У меня есть сортировка для каждого, как кажется требованием. Затем я хочу взять все отсортированные данные и применить шаблон.

Вот пример XML. У меня есть группа элементов журнала и элементов результата по отдельным путям, которые мне нужно отсортировать вместе на основе числового значения метки времени. В этом примере все уже отсортировано естественным образом, за исключением последнего элемента, значение числовой метки времени которого больше трех элементов результата, что означает, что он должен отображаться последним в выходных данных. Как написано, выходные данные будут отображать все элементы журнала, за которыми следуют все элементы результата в порядке их появления во входном XML.

<output>
  <logs>
    <log logtext="Username = " loglevel="DEBUG" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428014" />
    <log logtext="Password = " loglevel="DEBUG" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428027" />
    <log logtext="ServerURI = " loglevel="DEBUG" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428042" />
    <log logtext="TRACE TEST" loglevel="TRACE" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428084" />
    <log logtext="DEBUG TEST" loglevel="DEBUG" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428096" />
    <log logtext="INFO TEST" loglevel="INFO" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428109" />
    <log logtext="WARNING TEST" loglevel="WARN" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428120" />
    <log logtext="ERROR TEST" loglevel="ERROR" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428133" />
    <log logtext="Post-Result INFO Test" loglevel="INFO" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428353" />
  </logs>
  <results>
    <result name="Passed Test" resultformat="TEXT" resulttype="PASS" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428352" />
    <result name="Failed Test" resultformat="TEXT" resulttype="FAIL" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428352" />
    <result name="Running Processes" resultformat="TABLE" resulttype="NONE" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428352">
    </result>
  </results>
</output>

Вот соответствующие части XSL:

<xsl:template match="/">       
    <html>
       <body>                
        <xsl:for-each select="//logs/log | //results/result">
          <xsl:sort data-type="number" select="@numerictimestamp"/>
          <xsl:apply-templates select="self::node()" />
        </xsl:for-each>
      </body>
</html>
 </xsl:template>

  <xsl:template match="log">
    .... handle formatting of the log elements
  </xsl:template>

  <xsl:template match="result">
    .... handle formatting of the result elements
  </xsl:template>

Полагаю, это проблема области действия, так как сортировка применяется только к одному элементу в for-each, но я не уверен, что изменить, чтобы разрешить его и достичь того же результата. За исключением сортировки, этот XSL дает мне именно тот результат, который мне нужен.

EDIT1:

Обновление вопроса с включением измененного рабочего кода, включающего ответы и комментарии ниже. Сортировка не удалась из-за того, что сортируемые числа были слишком большими. Это значения меток времени, которые включают в себя миллисекунды, в частности, чтобы быть точными, поэтому иронично, что именно точность была причиной проблемы. Тем не менее, даже с более короткими числами, помещающими сортировку в для каждого, фактически не сортировалось больше чем один элемент.

Большинство примеров использования xsl: sort делают это в for-each. Я не знал, что вы можете включить его в шаблоны применения.

Следующая модификация работает правильно: (Обратите внимание, что я явно указал тип данных в качестве текста для ясности, я понимаю, что это по умолчанию)

  <xsl:apply-templates select="//logs/log | //results/result">       
    <!--The data-type value for the sort MUST be text, due to rounding errors introduced
    attempting to sort the numerictimestamp-->
    <xsl:sort data-type="text" select="@numerictimestamp"/>          
  </xsl:apply-templates>

Мне удалось сохранить остальную часть XSL без изменений.

1 Ответ

5 голосов
/ 24 января 2012

Делает ли это то, что вы хотите?

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
    <xsl:template match="/">
        <output>
            <xsl:apply-templates select="//log | //result">
                <xsl:sort select="@numerictimestamp"/>
            </xsl:apply-templates>
        </output>
    </xsl:template>

    <xsl:template match="log | result">
        <xsl:copy-of select="."/>
    </xsl:template>
</xsl:stylesheet>

Я думаю, что вы были правы, что for-each уменьшал область действия до текущего элемента

Другое дело, что преобразование ваших числовых атрибутов timestamp в числа вызывает округление.

Если я сделаю это:

<xsl:template match="log | result">
    <entry>
    <number><xsl:value-of select="number(@numerictimestamp)"/></number>
    <string><xsl:value-of select="@numerictimestamp"/></string>
    </entry>
</xsl:template>

Я вижу это:

<entry>
    <number>20120123170428132</number>
    <string>20120123170428133</string>
</entry>
<entry>
    <number>20120123170428352</number>
    <string>20120123170428353</string>
</entry>
<entry>
    <number>20120123170428352</number>
    <string>20120123170428352</string>
</entry>

Как я понимаю, тип данных числа XSLT соответствует IEEE 754, и википедия сообщает мне, что двойная точность с точностью до 15,95 цифр. Ваши номера 17 цифр

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