Как заменить uri пространства имен на xslt

#xml #xslt

#xml #xslt

Вопрос:

Как мне заменить uri пространства имен одного или нескольких элементов XML-сообщения, не зная заранее префикс пространства имен, который будет произвольно использоваться отправителем?

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

У меня есть решение, но оно приводит к ненужному мусору, который мне не нужен на выходе. Простой ввод:

 <?xml version="1.0" encoding="UTF-8"?>
<myThing xmlns:s="http://tempuri3.org/">
    <s:thisThing>
        <thatThing xmlns="http://cheapCookies.org/"/>
        <anotherThing xmlns="http://kingkong.org">
            <thisThing/>
        </anotherThing>
    </s:thisThing>
</myThing>
  

Это XSLT:

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

  <xsl:param name="sourceNamespace" select="'http://tempuri3.org/'" /> 
  <xsl:param name="targetNamespace" select="'http://tempuri.org'"/> 

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

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

    <xsl:template match="*">
        <xsl:choose>
            <xsl:when test="namespace-uri() = $sourceNamespace">
                <xsl:element name="{name()}" namespace="{$targetNamespace}">
                    <xsl:apply-templates select="node() | @*"/>
                </xsl:element>
            </xsl:when>

            <xsl:otherwise>
                <xsl:call-template name="identity"/>
            </xsl:otherwise>
        </xsl:choose>

    </xsl:template>
</xsl:stylesheet>
  

Это результат приведенного выше XSLT:

 <?xml version="1.0" encoding="utf-8"?>
<myThing xmlns:s="http://tempuri3.org/">
    <s:thisThing xmlns:s="http://tempuri.org">
        <thatThing xmlns="http://cheapCookies.org/" xmlns:s="http://tempuri3.org/"/>
        <anotherThing xmlns="http://kingkong.org" xmlns:s="http://tempuri3.org/">
            <thisThing/>
        </anotherThing>
    </s:thisThing>
</myThing>
  

Это желаемый результат:

 <?xml version="1.0" encoding="utf-8"?>
<myThing xmlns:s="http://tempuri.org/">
    <s:thisThing>
        <thatThing xmlns="http://cheapCookies.org/"/>
        <anotherThing xmlns="http://kingkong.org">
            <thisThing/>
        </anotherThing>
    </s:thisThing>
</myThing>
  

Комментарии:

1. » Префиксы, по определению, являются произвольными «, префиксы являются произвольными, пространства имен — нет. Из вашего описания неясно, знаете ли вы заранее пространства имен, используемые в источнике.

2. Я знаю URI исходного и целевого пространства имен, но я не буду знать префикс.

Ответ №1:

Я знаю URI исходного и целевого пространства имен,

Тогда вам, вероятно, следует сделать:

 <xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:old="http://tempuri3.org/"
exclude-result-prefixes="old">

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="old:*">
    <xsl:element name="{local-name()}" namespace="http://tempuri.org">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>
  

Результат может незначительно отличаться в зависимости от используемого процессора. Например, Saxon 6.5 вернет:

 <?xml version="1.0" encoding="UTF-8"?>
<myThing xmlns:s="http://tempuri3.org/">
  <thisThing xmlns="http://tempuri.org">
    <thatThing xmlns="http://cheapCookies.org/"/>
    <anotherThing xmlns="http://kingkong.org">
      <thisThing/>
    </anotherThing>
  </thisThing>
</myThing>
  

Комментарии:

1. Очень приятно! local-name() …. мне не сразу пришло в голову, что мне не нужен префикс на выходе.

2. Вы также можете использовать name() функцию, но из спецификации : процессоры XSLT могут использовать префикс QName, указанного в атрибуте name, при выборе префикса, используемого для вывода созданного элемента в формате XML; однако они не обязаны это делать .