2015-02-05 4 views
1

Мне нужно сравнить атрибуты XML, которые представляют целые числа, но могут быть заданы в десятичной или шестнадцатеричной форме (с префиксом 0x) с использованием XPath/XSLT-1.0.XPath 1.0, интерпретировать шестнадцатеричный атрибут как число

Вот (не работает) XSLT, чтобы продемонстрировать:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text" encoding="iso-8859-1" omit-xml-declaration="yes" /> 

    <xsl:template match="//node"> 
     <xsl:if test="@value &gt; 2"> 
      <xsl:value-of select="@value"/> 
     </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

Вот XML-для ввода:

<?xml version="1.0" encoding="UTF-8"?> 
<body> 
    <node value="1"/> 
    <node value="3"/> 
    <node value="0x03"/> 
</body> 

Здесь требуемый выход. Формат не важен; Важным является только то, что есть совпадение на втором и третьем узлах:

3 0x03 

Существует только совпадение на втором узле; шестнадцатеричный узел не интерпретируется как число с помощью XML. Может ли кто-нибудь подумать о разумном решении этой проблемы?

+0

Какой процессор XSLT вы используете? Это невозможно сделать за один шаг в XSLT 1.0. Вам нужно будет создать промежуточный результат (фрагмент результирующего дерева) с [преобразованными числами] (http://stackoverflow.com/questions/22905134/convert-hexa-to-integer-in-xslt) и от *, что * - с помощью функции расширения 'node-set()' вы можете выбрать узлы так, как вы хотите ('// node [@value > 2]'). Поскольку 'node-set()' недоступен везде, все зависит от версии вашего XSLT-процессора. – Tomalak

+0

@Tomalak Почему, по-вашему, необходимо иметь узел? –

+0

Процессор - msxsl. –

ответ

4

Формат не имеет значения;

Тогда для удобства я продемонстрирую с форматом XML в качестве выходного сигнала:

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:template match="/body"> 
    <xsl:copy> 
     <xsl:for-each select="node"> 
      <xsl:variable name="decimal"> 
       <xsl:choose> 
        <xsl:when test="starts-with(@value, '0x')"> 
         <xsl:call-template name="hex2num"> 
          <xsl:with-param name="hex" select="substring-after(@value, '0x')"/> 
         </xsl:call-template> 
        </xsl:when> 
        <xsl:otherwise> 
         <xsl:value-of select="@value"/> 
        </xsl:otherwise> 
       </xsl:choose> 
      </xsl:variable> 
      <xsl:if test="$decimal > 2"> 
       <xsl:copy-of select="."/> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

<xsl:template name="hex2num"> 
    <xsl:param name="hex"/> 
    <xsl:param name="num" select="0"/> 
    <xsl:param name="MSB" select="translate(substring($hex, 1, 1), 'abcdef', 'ABCDEF')"/> 
    <xsl:param name="value" select="string-length(substring-before('ABCDEF', $MSB))"/> 
    <xsl:param name="result" select="16 * $num + $value"/> 
    <xsl:choose> 
     <xsl:when test="string-length($hex) > 1"> 
      <xsl:call-template name="hex2num"> 
       <xsl:with-param name="hex" select="substring($hex, 2)"/> 
       <xsl:with-param name="num" select="$result"/> 
      </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="$result"/> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

</xsl:stylesheet> 

Применительно к следующему Тестовый вход:

<body> 
    <node value="1"/> 
    <node value="0x02"/> 
    <node value="3"/> 
    <node value="0x04"/> 
    <node value="0xB1"/> 
</body> 

производит это результат:

<?xml version="1.0" encoding="UTF-8"?> 
<body> 
    <node value="3"/> 
    <node value="0x04"/> 
    <node value="0xB1"/> 
</body> 
+0

Ницца, Майкл. Я разочарован, если нет более простого способа, но с ограничением на 1.0, что часто бывает. Я снимаю с тебя шляпу. Я проголосовал за ответ, потому что он очень информативен; Я не смогу проверить его в контексте до следующей недели, но, по-видимому, это сработает, и я тогда «приму» ответ. Спасибо. –

+0

@Captain С msxsl есть более простой способ сделать это. Запатентованно, но проще. См. Мой ответ. – Tomalak

+0

Интересно, что я случайно заметил, что коллега, имеющий дело с теми же данными XML, что и я, но для совершенно другой цели, должен был решить ту же проблему, нашел этот ответ с помощью Google и использовал его, не зная, что я разместил вопрос ! –

1

Поскольку вы сказали, что ваш процессор MSXSL, вы можете подключиться к msxsl расширений, которые позволяют вам define a script, что вы можете использовать для работы, что процессор XSLT сам не может сделать.

Следующая функция использует небольшую функцию JScript, которая преобразует все шестнадцатеричные числа, начинающиеся с 0x, в их десятичную копию.

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
    xmlns:script="http://tempuri.org/script" 
    exclude-result-prefixes="msxsl script" 
> 
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/> 

    <xsl:template match="/body"> 
    <xsl:copy> 
     <xsl:copy-of select="node[script:hexToDec(@value) &gt; 2]" /> 
    </xsl:copy> 
    </xsl:template> 

    <msxsl:script language="jscript" implements-prefix="script"><![CDATA[ 
    function hexToDec(nodeList) { 
     var firstNode, matches; 
     if (nodeList.length) { 
     firstNode = nodeList.nextNode(); 
     matches = /^\s*0x0*([0-9A-F]+)\s*$/i.exec(firstNode.text); 
     return matches ? parseInt(matches[1], 16) : firstNode.text; 
     } 
     return ""; 
    } 
    ]]></msxsl:script> 
</xsl:stylesheet> 

msxsl имен также позволяет более продвинутые способы расширения процессора XSLT, например, с помощью COM DLL, или код .NET, но для этого простого сценария JScript делает просто отлично.

+0

Привет @Tomalak. Это очень полезный подход и хороший пример того, как использовать скрипт с msxsl. Я не знал, что это возможно. В моем случае, на этот раз, по ряду внешних причин я буду использовать чистый подход XSLT. Для общего случая с несколькими атрибутами, которые требуют интерпретации/преобразования, сценарии выглядят как значительно более удобный и компактный подход. –

Смежные вопросы