#xml #xslt
#xml #xslt
Вопрос:
Как мне заменить uri пространства имен одного или нескольких элементов XML-сообщения, не зная заранее префикс пространства имен, который будет произвольно использоваться отправителем?
Я знаю, что формы этого вопроса задавались много раз, но каждый ответ, который я нахожу (здесь и на других сайтах), предполагает точное знание префикса. Префиксы, по определению, являются произвольными, и решение этой проблемы не должно требовать строгого знания используемого префикса.
У меня есть решение, но оно приводит к ненужному мусору, который мне не нужен на выходе. Простой ввод:
<?xml version="1.0" encoding="UTF-8"?>
<myThing xmlns:s="http://tempuri3.org/">
<s:thisThing>
<thatThing xmlns="http://cheapCookies.org/"/>
<anotherThing xmlns="http://kingkong.org">
<thisThing/>
</anotherThing>
</s:thisThing>
</myThing>
Это XSLT:
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="sourceNamespace" select="'http://tempuri3.org/'" />
<xsl:param name="targetNamespace" select="'http://tempuri.org'"/>
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="node() | @*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:choose>
<xsl:when test="namespace-uri() = $sourceNamespace">
<xsl:element name="{name()}" namespace="{$targetNamespace}">
<xsl:apply-templates select="node() | @*"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="identity"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Это результат приведенного выше XSLT:
<?xml version="1.0" encoding="utf-8"?>
<myThing xmlns:s="http://tempuri3.org/">
<s:thisThing xmlns:s="http://tempuri.org">
<thatThing xmlns="http://cheapCookies.org/" xmlns:s="http://tempuri3.org/"/>
<anotherThing xmlns="http://kingkong.org" xmlns:s="http://tempuri3.org/">
<thisThing/>
</anotherThing>
</s:thisThing>
</myThing>
Это желаемый результат:
<?xml version="1.0" encoding="utf-8"?>
<myThing xmlns:s="http://tempuri.org/">
<s:thisThing>
<thatThing xmlns="http://cheapCookies.org/"/>
<anotherThing xmlns="http://kingkong.org">
<thisThing/>
</anotherThing>
</s:thisThing>
</myThing>
Комментарии:
1. » Префиксы, по определению, являются произвольными «, префиксы являются произвольными, пространства имен — нет. Из вашего описания неясно, знаете ли вы заранее пространства имен, используемые в источнике.
2. Я знаю URI исходного и целевого пространства имен, но я не буду знать префикс.
Ответ №1:
Я знаю URI исходного и целевого пространства имен,
Тогда вам, вероятно, следует сделать:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:old="http://tempuri3.org/"
exclude-result-prefixes="old">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="old:*">
<xsl:element name="{local-name()}" namespace="http://tempuri.org">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Результат может незначительно отличаться в зависимости от используемого процессора. Например, Saxon 6.5 вернет:
<?xml version="1.0" encoding="UTF-8"?>
<myThing xmlns:s="http://tempuri3.org/">
<thisThing xmlns="http://tempuri.org">
<thatThing xmlns="http://cheapCookies.org/"/>
<anotherThing xmlns="http://kingkong.org">
<thisThing/>
</anotherThing>
</thisThing>
</myThing>
Комментарии:
1. Очень приятно! local-name() …. мне не сразу пришло в голову, что мне не нужен префикс на выходе.
2. Вы также можете использовать
name()
функцию, но из спецификации : процессоры XSLT могут использовать префикс QName, указанного в атрибуте name, при выборе префикса, используемого для вывода созданного элемента в формате XML; однако они не обязаны это делать .