Подтвердить что ты не робот

Как исключить записи xmlns = "", созданные преобразованием XSLT одного документа XML в другой документ XML

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

У меня есть XML, который выглядит примерно так:

<?xml version="1.0" encoding="utf-8"?>
<message>
  <cmd id="api_info">
    <api-version>1.0</api-version>
    <api-build>1.0.0.0</api-build>
  </cmd>
</message>

Теперь у меня есть преобразование XSLT, которое я применяю к этому XML. XSLT похож на следующее:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fo="http://www.w3.org/1999/XSL/Format"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:fn="http://www.w3.org/2005/xpath-functions"
                version="2.0">

    <xsl:output method="xml" version="1.0" indent="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates select="message"/>
    </xsl:template>

    <xsl:template match="message">
        <xsl:element name="message" xmlns="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="/message/cmd/@id">
        <xsl:variable name="_commandType" select="/message/cmd/@id"/>
        <xsl:element name="messageHeader">
            <xsl:element name="cmdType">
                <xsl:value-of select="$_commandType"/>
            </xsl:element>
        </xsl:element>

        <xsl:element name="messageBody">
            <xsl:choose>
                <xsl:when test="$_commandType = 'api_info'">
                    <xsl:element name="apiInfoBody">
                        <xsl:element name="apiVersion">
                            <xsl:value-of select="/message/cmd/api-version"/>
                        </xsl:element>
                        <xsl:element name="apiBuild">
                            <xsl:value-of select="/message/cmd/api-build"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
                <xsl:when test="$_commandType = 'communicationError'">
                    <xsl:element name="communicationErrorBody">
                        <xsl:element name="errorCode">
                            <xsl:value-of select="error-code"/>
                        </xsl:element>
                        <xsl:element name="badCmd">
                            <xsl:value-of select="bad-cmd"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
            </xsl:choose>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Выход, который я получаю, в основном то, что я хочу, и выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<message xmlns="http://www.companyname.com/schemas/product/Version001">
    <messageHeader xmlns="">
        <cmdType>api_info</cmdType>
    </messageHeader>
    <messageBody xmlns="">
        <apiInfoBody>
            <apiVersion>1.0</apiVersion>
            <apiBuild>1.0.0.0</apiBuild>
        </apiInfoBody>
    </messageBody>
</message>

Но мне не нужны атрибуты xmlns = "" в элементах <messageHeader> и <messageBody> .

Теперь я обнаружил, что если я явно укажу пространство имен в XSLT для этих элементов, то нежелательный атрибут будет передан на один уровень дочерним элементам этих атрибутов.

Я мог бы просто пройти через весь XSLT и явно добавить атрибут xmlns = " http://www.companyname.com/schemas/product/Version001 для каждого из моих определений xsl: element, но я знаю, что должен быть более элегантный способ. Мы, программисты, слишком ленивы, чтобы не иметь ярлыка для такого рода глупостей. Если бы мой XSLT не" t состоит из чего-то простого, как укороченный пример, у меня возникает соблазн сделать это таким образом. Но я знаю, что должен быть лучший способ.

Кто-нибудь знает, что мне здесь не хватает?

Спасибо,

AlarmTripper

4b9b3361

Ответ 1

Используйте префиксы exclude-result в теге xsl: stylesheet с префиксом "#default"

Ссылка в w3c для этого ЗДЕСЬ

РЕДАКТОР: Хорошо, я должен был внимательно изучить ваш XSL. Переместите xmlns в теге сообщения до тега таблицы стилей. Это поместит ВСЕ элементы результата в одно и то же пространство имен и приведет к одному атрибуту пространства имен в теге сообщения. Я запускал это в Oxygen/XML и получил нужный результат.

Ответ 2

Хорошо, я понял это.

XSLT, который я хочу, выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fo="http://www.w3.org/1999/XSL/Format"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:fn="http://www.w3.org/2005/xpath-functions"
                exclude-result-prefixes="xsl fo xs fn">

    <xsl:output method="xml" version="1.0" indent="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates select="message"/>
    </xsl:template>

    <xsl:template match="message">
        <message namespace="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </message>
    </xsl:template>

    <xsl:template match="/message/cmd/@id">
        <xsl:variable name="_commandType" select="/message/cmd/@id"/>

        <xsl:element name="messageHeader">
            <xsl:element name="cmdType">
                <xsl:value-of select="$_commandType"/>
            </xsl:element>
        </xsl:element>

        <xsl:element name="messageBody">
            <xsl:choose>
                <xsl:when test="$_commandType = 'api_info'">
                    <xsl:element name="apiInfoBody">
                        <xsl:element name="apiVersion">
                            <xsl:value-of select="/message/cmd/api-version"/>
                        </xsl:element>
                        <xsl:element name="apiBuild">
                            <xsl:value-of select="/message/cmd/api-build"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
                <xsl:when test="$_commandType = 'communicationError'">
                    <xsl:element name="communicationErrorBody">
                        <xsl:element name="errorCode">
                            <xsl:value-of select="error-code"/>
                        </xsl:element>
                        <xsl:element name="badCmd">
                            <xsl:value-of select="bad-cmd"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
            </xsl:choose>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Исправленное изменение заключалось в том, чтобы добавить атрибут exclude-result-prefixes в элемент < xsl: stylesheet > и изменить раздел, который был:

    <xsl:template match="message">
        <xsl:element name="message" xmlns="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </xsl:element>
    </xsl:template>

вместо этого:

    <xsl:template match="message">
        <message namespace="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </message>
    </xsl:template>

И теперь я снова счастлив.

Есть, вероятно, лучшие способы сделать это, но это работает для меня. Любые будущие предложения по-прежнему приветствуются.

Ответ 3

Джим Гаррисон (обновленный) ответ - это все, что вам нужно. Но обновленная таблица стилей, которую вы отправили, выводит атрибут "namespace" в результате, поэтому я не уверен, что это хорошо.

Ключевое значение для понимания - это то, как работает пространство имен по умолчанию. Не думайте о xmlns как атрибуте, который вы можете вывести на результат. Вместо этого подумайте об этом как о лексической детали вашей таблицы стилей, целью которой является установить пространство имен по умолчанию для всего под ним (сам элемент и каждый из его потомков до тех пор, пока они не переопределены). (В свою очередь, он имеет ту же функцию в XML-результате, который имеет совсем другую структуру, чем сама таблица стилей.)

Литеральные элементы результата в вашей таблице стилей (например, <message> ), а также инструкции < xsl: element > (например, < xsl: element name= "message" > ), оба принимают пространство имен по умолчанию, когда указанное имя не использует префикс. Если вы хотите, чтобы все они занимали одно и то же пространство имен, тогда вам нужно разместить пространство имен по умолчанию в верхней части таблицы стилей, как предположил Джим Гаррисон.

В противном случае вы столкнетесь с некоторыми элементами, которые не находятся в этом пространстве имен, поэтому результат содержал xmlns = "" (отмена пространства имен для этих элементов).