Римская система счисления не является позиционной. Число в ней записывается путем прибавления или вычитания фиксированного количества римских цифр. Если следующий символ имеет меньшее или такое же значение, то производится добавление, иначе вычитание.
Элемент xsl:number дает удобный способ преобразовать число в римскую запись. Однако обратное преобразование приходится выполнять самостоятельно. Показанный выше рекурсивный шаблон решает эту задачу прямолинейно и очень похож на приведенный в книге Jeni Tennison XSLT and XPath on the Edge (M&T Books, 2001).
Имеются два мелких подводных камня, но в большинстве случаев они не приводят к неприятностям.
Первый заключается в том, что это решение не работает, когда число записано римскими цифрами в разных регистрах (например, IiI). Такие аномалии вряд ли встретятся в нормальном источнике данных, тем не менее приведенный код и не отбросит входные данных как некорректные, и правильного результата не даст. Если добавить преобразование к единому регистру, то некорректные входные данные можно будет либо отвергнуть, либо нормально обработать.
Вторая неприятность связана с тем фактом, что не существует стандартного представления в римской записи чисел, больших 1000. Процессоры Saxon и Xalan сцепляют в этом случае буквы M, но другие могут поступать иначе.
Если по какой-то причине вам не нравится хранить данных о римских числительных в таблице стилей, то можете воспользоваться следующим выражением на языке XPath 1.0 для декодирования:
1 2 3 4 5 6 7 8 910
<xsl:variablename="roman-value"select="($c = 'i' or $c = 'I') * 1 + ($c = 'v' or $c = 'V') * 5 + ($c = 'x' or $c = 'X') * 10 + ($c = 'l' or $c = 'L') * 50 + ($c = 'c' or $c = 'C') * 100 + ($c = 'd' or $c = 'D') * 500 + ($c = 'm' or $c = 'M') * 1000)"/>
В XSLT 2.0 можно воспользоваться вложенным выражением if-the-else или организовать справочную таблицу из последовательности: