Это наиболее часто задаваемые вопросы по XPath, XML и XSLT.Найдите «пространство имен по умолчанию и выражения XPath».
Что касается решения :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="http://india.com/states">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:element name="{name()}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="*[not(ancestor-or-self::x:city)]">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
, когда это преобразование применяется к предоставленномуXML-документ :
<country xmlns="http://india.com/states" version="1.0">
<state>
<city>
<name>DELHI</name>
</city>
</state>
</country>
желаемый результат получен :
<city>
<name>DELHI</name>
</city>
Объяснение :
В XPath нефиксированное имя элемента всегда считается находящимся в «пространстве имен».Однако каждое имя элемента в предоставленном XML-документе находится в непустом пространстве имен (пространство имен по умолчанию "http://india.com/states"
).Поэтому //city
не выбирает ни одного узла (так как в документе XML нет элемента, который не является пространством имен), а //x:city
, где x:
привязан к пространству имен "http://india.com/states"
выбирает все элементы города (которые находятся в пространстве имен"http://india.com/states"
).
В этом преобразовании есть два шаблона.Первый шаблон соответствует любому элементу и создает его заново, но в пространстве без имен.Он также копирует все атрибуты и затем применяет шаблоны к дочерним узлам этого элемента.
Второй шаблон переопределяет первый для всех элементов, которые не являются предками элемента city
илине элемент city
.Действие здесь заключается в применении шаблонов ко всем дочерним узлам.
ОБНОВЛЕНИЕ : ОП изменил вопрос, спрашивая, почему в результатеобработка нового измененного XML-документа:
<country xmlns="http://india.com/states" version="1.0">
<state>
<city>
<name>DELHI</name>
</city>
</state>
<state2>
<city2>
<name2>MUMBAI</name2>
</city2>
</state2>
</country>
Чтобы not для создания текста "MUMBAI", приведенное выше преобразование необходимо слегка изменить - игнорировать (не копировать)любой текстовый узел, у которого нет предка x:city
.Для этого мы добавляем следующий однострочный пустой шаблон:
<xsl:template match="text()[not(ancestor::x:city)]"/>
Теперь все преобразование становится :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="http://india.com/states">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:element name="{name()}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="*[not(ancestor-or-self::x:city)]">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()[not(ancestor::x:city)]"/>
</xsl:stylesheet>
ирезультат по-прежнему в розыске, правильный :
<city>
<name>DELHI</name>
</city>