Есть ли способ в XSLT управлять выбором префиксов пространства имен в выходных элементах?
В моем конкретном случае я фактически хочу преобразовать ввод, который выглядит как
<h:html xmlns:h='http://www.w3.org/1999/xhtml'
xmlns:m='http://www.w3.org/1998/Math/MathML'>
....
<h:p>Equation: <m:math>...</m:math></h:p>
в
<html xmlns='http://www.w3.org/1999/xhtml'>
....
<p>Equation: <math xmlns='http://www.w3.org/1998/Math/MathML'>...</math></p>
То есть преобразование идентичности, которое просто изменяет префиксы пространства имен, чтобы использовать пространство имен по умолчанию для элементов XHTML и MathML по мере необходимости.
Это завершающий шаг в конце рабочего процесса с использованием чистого XML. Вышеупомянутое, конечно, эквивалентно в терминах XML и, следовательно, в терминах XHTML, но браузеры, похоже, не всегда знают об этом (в моих не очень систематических тестах Firefox справляется с обоими вышеперечисленными в смысле рендеринга их как математики — Браво, Firefox! — Safari справляется со вторым, но не с первым, Chrome тоже не справляется; на самом деле я ориентируюсь на читателей EPUB, но кажется мудрым пессимистично относиться к тамошним парсерам XHTML). Попытка с элементом <output method='html'/>
XSLT не влияет на результат. В Руководстве по совместимости с XHTML не упоминаются пространства имен, что довольно удивительно. Добавление объявлений типа документа и даже хак <meta http-equiv=''...>
для подсказки application/xhtml+xml, похоже, не имеет никакого значения для поведения браузеров.
В спецификации XSLT 1.0 я не вижу ничего, что бы это контролировало. Упомянутый там псевдоним пространства имен решает другую проблему; игра с пространствами имен по умолчанию в XSLT не дает никаких подсказок, которые libxslt
, похоже, склонны принимать. Другие вопросы об обмене стеками (например, этот или этот) в значительной степени связаны с непониманием XSLT и пространств имен. Я уверен, что мне удалось добиться этого в какой-то момент моего долгого прошлого XSLT, но если бы я это сделал, я не смог бы его воскресить.
Я бы предпочел решение в XSLT 1.0 просто потому, что у меня есть инструменты и опыт для быстрого использования, в libxslt и xsltproc
(Saxon — действительно замечательная вещь, но я не хочу платить стоимость запуска Java для возможно, множество последовательных преобразований). Это может быть то, что вынуждает меня к более поздней версии XSLT, конечно, если более поздняя версия действительно единственная вещь, которая может помочь.
Из (не очень тщательного) взгляда на спецификацию XSLT 3 (например, раздел 11.1) я не вижу ничего, что явно решает эту проблему.
Если я лаю не по тому дереву или если известно, что процессоры EPUB постоянно лучше осведомлены о пространствах имен, так что я на самом деле решаю не ту часть проблемы, я также открыт для этой информации.
Вам понадобится преобразование
<xsl:template match = "*">
<xsl:element name = "{local-name()}" namespace = "namespace-uri()">
<xsl:apply-templates select = "@* | node()"/>
</xsl:element>
</xsl:template>
Настройте шаблон преобразования удостоверений для остальных.
И в XSLT 1 вы как бы полагаетесь на милость процессора XSLT и его сериализатора, чтобы получить желаемый результат, но я думаю, что для приведенного выше шаблона вы можете ожидать некоторой согласованности даже в мире 1.0.
Это действительно очень хорошо работает на практике, в том смысле, что это, кажется, дает сериализатору достаточно подсказок. Сериализатор не полностью понимает подсказку (как вы предлагаете): любые шаблоны, обрабатываемые в этой конструкции, которые содержат, например, <h:p xmlns:h='http://www.w3.org/1999/xhtml'>...</h:p>
, к сожалению, сериализуются с этим префиксом, а не с префиксом по умолчанию, который все еще находится в области действия на тот момент. Это означает, что я не могу оставить элементы XSLT в пространстве имен по умолчанию, но... я буду жить. Спасибо, Мартин, что успокоил меня, я ничего не упускаю.
Это выглядит очень многообещающе, и это работает в простом случае, который я пробовал. Настоящий код, конечно, немного сложнее, чем в моем вопросе, но я попробую и вернусь к этому ответу.