Как удалить пространства имен из XML с помощью XSLT - PullRequest
19 голосов
/ 11 марта 2011

У меня есть 150 МБ (иногда может быть и больше) XML-файла. Мне нужно удалить все пространства имен. Это на Visual Basic 6.0, поэтому я использую DOM для загрузки XML. С загрузкой все в порядке, сначала я был настроен скептически, но почему-то эта часть работает нормально.

Я пробую следующее XSLT , но оно также удаляет все остальные атрибуты. Я хочу сохранить все атрибуты и элементы, мне просто нужно удалить пространства имен. Видимо, это потому, что у меня есть xsl:element, но не атрибут. Как я могу включить атрибуты там?

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="UTF-8" />
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Ответы [ 3 ]

30 голосов
/ 04 мая 2011

Ваш XSLT также удаляет атрибуты, потому что у вас нет шаблона, который бы копировал их.<xsl:template match="*"> соответствует только элементам, а не атрибутам (или тексту, комментариям или инструкциям по обработке).

Ниже приведена таблица стилей, которая удаляет все определения пространства имен из обработанного документа, но копирует все другие узлы и значения: элементы, атрибуты,комментарии, текст и инструкции по обработке.Обратите внимание на 2 вещи

  1. Копирование атрибутов как таковых недостаточно для удаления всех пространств имен.Также атрибут может принадлежать пространству имен, даже если содержащий элемент не принадлежит пространству имен.Поэтому также необходимо создавать атрибуты, такие как элементы.Создание атрибутов выполняется с помощью элемента <xsl:attribute>.
  2. Действительный документ XML не может содержать элемент, имеющий два или более атрибутов с одинаковым расширенным именем, но элементы могут содержать несколько атрибутов с одинаковым локальным именем , если атрибутыимеют разные пространства имен. Это означает, что удаление префикса пространства имен из имени атрибута приведет к потере данных, если есть элемент, имеющий по крайней мере два атрибута с одинаковым локальным именем.Другой один из этих атрибутов будет удален (или перезаписан).

... и код:

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

    <xsl:output indent="yes" method="xml" encoding="utf-8" omit-xml-declaration="yes"/>

    <!-- Stylesheet to remove all namespaces from a document -->
    <!-- NOTE: this will lead to attribute name clash, if an element contains
        two attributes with same local name but different namespace prefix -->
    <!-- Nodes that cannot have a namespace are copied as such -->

    <!-- template to copy elements -->
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>

    <!-- template to copy attributes -->
    <xsl:template match="@*">
        <xsl:attribute name="{local-name()}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>

    <!-- template to copy the rest of the nodes -->
    <xsl:template match="comment() | text() | processing-instruction()">
        <xsl:copy/>
    </xsl:template>

</xsl:stylesheet>

Вы также можете использовать <xsl:template match="node()"> вместо этого последнего шаблонано тогда вы должны использовать атрибут priority, чтобы элементы не соответствовали этому шаблону.

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

Как включить туда атрибуты?

Просто добавьте этот шаблон к тому, который у вас уже есть:

<xsl:template match="@*">
    <xsl:copy/>
</xsl:template>
0 голосов
/ 18 ноября 2016
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="/">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
<xsl:template match="@*">
    <xsl:attribute name="{local-name()}">
        <xsl:value-of select="current()"/>
    </xsl:attribute>
</xsl:template>
<xsl:template match="*">
    <xsl:element name="{local-name()}">
        <xsl:apply-templates select="@* | * | text()"/>
    </xsl:element>
</xsl:template>
<xsl:template match="text()">
    <xsl:copy>
        <xsl:value-of select="current()"/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>
...