XSLT: Как удалить самозакрывающийся элемент - PullRequest
0 голосов
/ 16 марта 2010

У меня большой xml-файл, который содержит много самозакрывающихся тегов. Как можно удалить все их с помощью XSLT.

например.

<?xml version="1.0" encoding="utf-8" ?>
<Persons>
  <Person>
    <Name>user1</Name>
    <Tel />
    <Mobile>123</Mobile>
  </Person>
  <Person>
    <Name>user2</Name>
    <Tel>456</Tel>
    <Mobile />
  </Person>
  <Person>
    <Name />
    <Tel>123</Tel>
    <Mobile />
  </Person>
  <Person>
    <Name>user4</Name>
    <Tel />
    <Mobile />
  </Person>
</Persons>

Я ожидаю результата:

* +1007 *

Примечание: есть тысячи различных элементов, как я могу программно удалить все самозакрывающиеся теги. Другой вопрос, как удалить пустой элемент, такой как <name></name>.

Может кто-нибудь помочь мне в этом? Большое спасибо.

Ответы [ 5 ]

9 голосов
/ 16 марта 2010

Закрытые теги эквивалентны пустым тегам. Вы можете удалить все пустые теги, но у вас нет возможности узнать, были ли они автоматически закрыты во входном XML или нет (<tag/> и <tag></tag> неразличимы).

<!-- the identity template copies everything that has no special handler -->
<xsl:template match="node()|@*">
  <xsl:copy>
    <xsl:apply-templates select="node()|@*" />
  </xsl:copy>
</xsl:template>

<!-- special handler for elements that have no child nodes:
     they are removed by this empty template -->
<xsl:template match="*[not(node())]" />

Если элементы, содержащие только пробелы, по вашему определению также являются «пустыми», то замените второй шаблон на:

* +1007 *
1 голос
/ 16 марта 2010

С точки зрения XML, нет разницы между «самозакрывающимся» элементом и пустым элементом (см. spec ).

Вот преобразование для удаления всех пустых элементов:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" encoding="utf-8" />
    <xsl:strip-space elements="*" />

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

</xsl:stylesheet>
0 голосов
/ 18 марта 2010

Причина опубликования этого ответа: что вы не приняли ни одного из существующих ответов пока нет.

Хорошо. Это очень простая задача XSLT. Просто сопоставьте узел с текстовыми данными как ноль и закройте тег шаблона, чтобы узел не отображался в выходных данных.
вот так, <xsl:template match=*[.='']/> добавьте его вместе с вашим шаблоном идентификации. Подобно тому, как Томолак прибил.

Проблема с этим подходом заключается в том, что он удаляет даже ваш родительский узел (например, тег <Person/>), если он равен нулю.

Если это ваш xml:

<Persons>
   <Person>
     <data>text</data>
     <data2>text</data2>
     <data3/>
   </Person>
   <Person/>
</Persons>

Из приведенного выше xml даже тег удаляется. Таким образом, выходной XML будет:

<Persons>
   <Person>
     <data>text</data>
     <data2>text</data2>
   </Person>
</Persons>

Если вы хотите избежать этого, добавьте исключение.

<xsl:template match="*[name()!='Person' and not(node())]"/>

Добавьте свой шаблон личности. Ваш XSLT будет:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
  <xsl:template match="*[name()!='Person' and not(node())]"/>
</xsl:stylesheet>

И выходной xml будет:

<Persons>
   <Person>
     <data>text</data>
     <data2>text</data2>
   </Person>
   <Person/>
</Persons>
0 голосов
/ 16 марта 2010

Вы можете удалить все пустые элементы - те, которые не имеют вложенных элементов и объявленных атрибутов. Если это решение работает для вас, вы можете сделать следующее:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="*">
    <xsl:if test="string(.) != '' or descendant-or-self::*/@*[string(.)]">
      <xsl:element name="{name()}" >
        <xsl:copy-of select="@*[string(.)]"/>
        <xsl:apply-templates select="* | text()" />
      </xsl:element>
    </xsl:if>
  </xsl:template>

  <xsl:template match="text()">
    <xsl:value-of select="."/>
  </xsl:template>

</xsl:stylesheet>
0 голосов
/ 16 марта 2010

Возможно, вы захотите проверить, нужны ли они. Это должно выглядеть примерно так: use = "required". Также проверьте, являются ли они: type = "nonEmptyString".

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