XSLT для удаления тегов / атрибутов, принадлежащих пространству имен - PullRequest
10 голосов
/ 11 июня 2011

Я пытаюсь использовать XSLT для удаления тегов / атрибутов, принадлежащих пространству имен.Сложность состоит в том, что теги из разных пространств имен могут быть встроены друг в друга.

Пример:

<?xml version="1.0" encoding="utf-8"?>
<Collection xmlns="http://s0" xmlns:ns1="http://s1">
  <Identifier Name="CollectionX"
          ns1:GlobalID="{E436833B-B0A6-4E0D-804B-60052B767AE3}"
          ns1:LocalID="{0130C866-7A91-4544-A82B-E0C0F2E3BCB2}"  />

  <Properties>
    <ns1:Collectible>1982</ns1:Collectible>
    <Displayed>Reserved</Displayed>
    <Picture>Reserved.jpeg</Picture>
  </Properties>

  <WeakLinks>
    <Link Type="resource" Language="en-us"/>
  </WeakLinks>

</Collection>

Я хочу отфильтровать все теги / свойства, которые не принадлежат ns1, пока онине имеют детей ns1.

Таким образом, результат должен быть:

<?xml version="1.0" encoding="utf-8"?>
<Collection xmlns="http://s0" xmlns:ns1="http://s1">
  <Identifier 
      ns1:GlobalID="{E436833B-B0A6-4E0D-804B-60052B767AE3}"
      ns1:LocalID="{0130C866-7A91-4544-A82B-E0C0F2E3BCB2}"  />

  <Properties>
    <ns1:Collectible>1982</ns1:Collectible>
  </Properties>

</Collection>

Как я могу подтвердить это с помощью XSLT?Любая помощь?

Ответы [ 2 ]

6 голосов
/ 11 июня 2011

Это преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ns1="http://s1">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match=
 "*[not(attribute::ns1:*)
  and
    not(descendant-or-self::ns1:*)
   ]
 |
  @*[not(namespace-uri()='http://s1')]
 "/>
</xsl:stylesheet>

при применении к предоставленному документу XML:

<Collection xmlns="http://s0" xmlns:ns1="http://s1">
    <Identifier Name="CollectionX"
      ns1:GlobalID="{E436833B-B0A6-4E0D-804B-60052B767AE3}"
      ns1:LocalID="{0130C866-7A91-4544-A82B-E0C0F2E3BCB2}"  />
    <Properties>
        <ns1:Collectible>1982</ns1:Collectible>
        <Displayed>Reserved</Displayed>
        <Picture>Reserved.jpeg</Picture>
    </Properties>
    <WeakLinks>
        <Link Type="resource" Language="en-us"/>
    </WeakLinks>
</Collection>

дает желаемый, правильный результат :

<Collection xmlns="http://s0" xmlns:ns1="http://s1">
   <Identifier ns1:GlobalID="{E436833B-B0A6-4E0D-804B-60052B767AE3}"
   ns1:LocalID="{0130C866-7A91-4544-A82B-E0C0F2E3BCB2}"/>
   <Properties>
      <ns1:Collectible>1982</ns1:Collectible>
   </Properties>
</Collection>

Объяснение

  1. Правило идентификации (шаблон) копирует каждый узел "как есть"".

  2. Существует только один шаблон, переопределяющий правило идентификации. Этот шаблон не имеет тела - это означает, что он эффективно фильтрует (удаляет) любой совпадающий узел, который будет скопирован в выходные данные . Совпадающие узлы - это именно те, которые должны быть отфильтрованы: 1) любой элемент, который не имеет атрибутов, принадлежащих пространству имен, к которому привязан префикс ns1:, а также сам не принадлежит этому пространству имен и также имеет нет дочерних узловых элементов, принадлежащих этому пространству имен. И 2) любой атрибут, который не принадлежит этому пространству имен.

Помните : переопределение правила идентификации является наиболее фундаментальным и мощным шаблоном проектирования XSLT. Подробнее об этом шаблоне дизайна можно узнать здесь .

1 голос
/ 11 июня 2011

Вы можете выбрать элементы с пространством имен ns1, используя ns1:*.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:ns1="http://s1">
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@ns1:* | 
                                   node()[attribute::ns1:* | 
                                          descendant-or-self::ns1:*] | 
                                   text() | comment() | processing-instruction()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Обновление

Я обновил XPath для соответствующих атрибутов до @ns1:*, чтобы захватывать только атрибуты с требуемым пространством имен.Я также исправил поддержку комментариев и обработки инструкций по работе в моем тестировании.С учетом следующего XML

<?xml version="1.0" encoding="utf-8"?>
<Collection xmlns="http://s0" xmlns:ns1="http://s1">
  <Identifier Name="CollectionX"
          ns1:GlobalID="{E436833B-B0A6-4E0D-804B-60052B767AE3}"
          ns1:LocalID="{0130C866-7A91-4544-A82B-E0C0F2E3BCB2}"  />
<!-- comment -->
  <Properties>
    <ns1:Collectible>1982</ns1:Collectible>
    <Displayed>Reserved</Displayed>
    <Picture>Reserved</Picture>
  </Properties>

  <WeakLinks>
    <Link Type="resource" Language="en-us"/>
  </WeakLinks>

</Collection>

Приведенный выше XSL производит этот вывод (протестирован с Saxon и MSXML).

<?xml version="1.0" encoding="UTF-8"?>
<Collection xmlns="http://s0" xmlns:ns1="http://s1">
  <Identifier ns1:GlobalID="{E436833B-B0A6-4E0D-804B-60052B767AE3}" 
              ns1:LocalID="{0130C866-7A91-4544-A82B-E0C0F2E3BCB2}"/>
  <!-- comment -->
  <Properties>
    <ns1:Collectible>1982</ns1:Collectible>
  </Properties>
</Collection>

Обновление 2

Я удалил свою предыдущую ссылку на атрибуты без пространства имен. В соответствии со спецификацией XPath , которая очень хорошо резюмируется здесь @ Dimitre.Novatchev , атрибут без префикса пространства имен принадлежит «пространству без имен», а не пространству имен по умолчанию или пространству именродительского узла.Если вы хотите сопоставить их, добавьте @*[parent::ns1:* and namespace-uri()=''] | к выражению соответствия в <apply-templates ...>.Это применимо к ситуации, подобной <ns1:Collectible WhatIsMyNamespace="no-namespace">, где вы хотите соответствовать WhatIsMyNamespace="no-namespace".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...