Удалите пространство имен и извлеките подмножество XML-файла, используя XSL - PullRequest
4 голосов
/ 05 июля 2011

Когда мой Input Xml как:

 <country>
       <state>
           <city>
               <name>DELHI</name>            
           </city>
      </state>
    </country>

Для требуемого вывода, как показано ниже:

<city>
  <name>DELHI</name>            
</city

Следующий xsl работает нормально:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" omit-xml-declaration="yes" />
    <xsl:template match="/">
        <xsl:copy-of select="//city">
        </xsl:copy-of>
    </xsl:template>
</xsl:stylesheet>

НО ЖЕ XSL НЕ РАБОТАЕТ НАД ВЫШЕ ВВОДА XML, ЕСЛИ ПРОБЕЛ ИМЯ ДОБАВЛЕНО: Как показано ниже:

<country xmlns="http://india.com/states" version="1.0">
   <state>
       <city>
           <name>DELHI</name>            
       </city>
  </state>
</country>

Я хочу удалить пространство имен вместе с элементом city длябыть скопированы.

Любая помощь будет оценена.Спасибо

Ответы [ 2 ]

3 голосов
/ 05 июля 2011

Это наиболее часто задаваемые вопросы по 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>

Объяснение :

  1. В XPath нефиксированное имя элемента всегда считается находящимся в «пространстве имен».Однако каждое имя элемента в предоставленном XML-документе находится в непустом пространстве имен (пространство имен по умолчанию "http://india.com/states").Поэтому //city не выбирает ни одного узла (так как в документе XML нет элемента, который не является пространством имен), а //x:city, где x: привязан к пространству имен "http://india.com/states" выбирает все элементы города (которые находятся в пространстве имен"http://india.com/states").

  2. В этом преобразовании есть два шаблона.Первый шаблон соответствует любому элементу и создает его заново, но в пространстве без имен.Он также копирует все атрибуты и затем применяет шаблоны к дочерним узлам этого элемента.

  3. Второй шаблон переопределяет первый для всех элементов, которые не являются предками элемента 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>
0 голосов
/ 05 июля 2011

Вы можете получить желаемый результат, используя шаблон как:

 <xsl:template match="*[not(ancestor-or-self::x:*[starts-with(name(),'city')])]">
  <xsl:apply-templates/>
 </xsl:template>

или

 <xsl:template match="/">
     <xsl:apply-templates select="//x:*[starts-with(name(),'city')]"/>
 </xsl:template>

Протестировано с Microsoft (R) XSLT Processor Version 4.0 на вашем новом входе дает:

<city>
   <name>DELHI</name>
</city>
<city2>
   <name2>MUMBAI</name2>
</city2>
...