XSL - копировать элементы, но удалять неиспользуемые пространства имен
У меня есть XML, который объявляет пространство имен, которое используется только для атрибутов, например:
<?xml version="1.0" encoding="UTF-8"?>
<a xmlns:x="http://tempuri.com">
<b>
<c x:att="true"/>
<d>hello</d>
</b>
</a>
Я хочу использовать XSL для создания копии выбранных узлов и их значений - избавления от атрибутов. Поэтому мой желаемый результат:
<?xml version="1.0" encoding="UTF-8"?>
<b>
<c />
<d>hello</d>
</b>
У меня есть XSL, который почти делает это, но я не могу помешать ему помещать объявление пространства имен в элемент верхнего уровня вывода. Мой XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates select="/a/b"/>
</xsl:template>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Первый элемент вывода - <b xmlns:x="http://tempuri.com">
вместо <b>
. Я попытался объявить пространство имен в XSL и поместить префикс в список exclude-result-prefixes
, но это, похоже, не имеет никакого эффекта. Что я делаю неправильно?
UPDATE: я обнаружил, что, объявив пространство имен в XSL и используя атрибут extension-element-prefixes
, но это кажется неправильным! Я думаю, я мог бы использовать это, но я хотел бы знать, почему exclude-result-prefixes
не работает!
UPDATE: На самом деле кажется, что это решение extension-element-prefixes
работает только с встроенным XSLT-движком XMLSpy, а не с MSXML.
Ответы
Ответ 1
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:x="http://tempuri.com">
<xsl:template match="/">
<xsl:apply-templates select="/a/b"/>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:copy/>
</xsl:template>
<!-- This empty template is not needed.
Neither is the xmlns declaration above:
<xsl:template match="@x:*"/> -->
</xsl:stylesheet>
Я нашел объяснение здесь.
Майкл Кей написал:
Префикс exclude-result влияет только на пространства имен, скопированные с таблица стилей с помощью литерального элемента результата, это не влияет на копирование пространства имен из исходных документов.
Ответ 2
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="http://tempuri.com"
exclude-result-prefixes="x"
>
<!-- the identity template copies everything 1:1 -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<!-- this template explicitly cares for namespace'd attributes -->
<xsl:template match="@x:*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Ответ 3
Попробуйте это (обратите внимание на атрибут copy-namespaces='no'
):
<xsl:template match="node()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
Ответ 4
Это приведет к удалению пространства имен x из вывода.
<xsl:namespace-alias result-prefix="#default" stylesheet-prefix="x" />
Не забывайте делать две вещи, когда вы имеете дело с пространством имен по умолчанию. Сначала сопоставьте его с чем-то в теге stylesheet, а затем удалите его с помощью псевдонима пространства имен.