Изменение значения пространства имен в преобразовании XSL?

Я не уверен, что это возможно, так как я новичок в XSLT и прочем, но, может быть, кто-то из вас мог бы мне помочь? Это немного сложно, и я не нашел ничего подобного в Интернете:

Проблема в том, что у меня есть входной xml с объявленными пространствами имен и всем остальным, и мне нужно лишь внести в него небольшие изменения (добавление или удаление атрибутов или перемещение их в другие места). Но в то же время я должен обновить ссылки на пространство имен в теге документа документа. Так, например, входной xml может выглядеть примерно так:

<order
  xmlns="some.url.01"
  xmlns:ns2="some.other.url"
  xmlns:ns3="another.one"
>
  <orderEntry>
    <orderControl>
      <mandant>test</mandant>
      <businessUnit>test</businessUnit>
      <inboundChannel>test</inboundChannel>
      <timestamp>timestamp</timestamp>
      <requestedDocuments>
        <ns2:document>orderForm</ns2:document>
      </requestedDocuments>
    </orderControl>
  </orderEntry>
</order>

результирующий xml должен выглядеть так:

<order
  xmlns="some.url.02"
  xmlns:ns2="some.other.url.02"
  xmlns:ns3="another.one.02"
>
  <orderEntry>
    <orderControl>
      <mandant>test</mandant>
      <businessUnit>test</businessUnit>
      <inboundChannel>test</inboundChannel>
      <!-- deleted timestamp for example -->
      <requestedDocuments>
        <ns2:document>orderForm</ns2:document>
      </requestedDocuments>
    </orderControl>
  </orderEntry>
</order>

но единственное, что я получаю, это:

<order
  xmlns="some.url.02"
>
  <orderEntry>
    <orderControl>
      <mandant>test</mandant>
      <businessUnit>test</businessUnit>
      <inboundChannel>test</inboundChannel>
      <!-- deleted timestamp for example -->
      <requestedDocuments>
        <ns2:document xmlns:ns2="some.other.url.02">orderForm</ns2:document>
      </requestedDocuments>
    </orderControl>
  </orderEntry>
</order>

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

Мой XSLT выглядит так:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="some.url.02"
  xmlns:ns2="some.other.url.02"
  xmlns:ns3="another.one.02"
>
  <xsl:output method="xml" version="1.0" encoding="UTF-8" standalone="yes" indent="yes"/>

  <xsl:strip-space elements="*"/>

  <xsl:template match="*">
    <xsl:choose>
      <xsl:when test="name(.) != 'timestamp'">
        <xsl:element name="{node-name(.)}">
          <xsl:apply-templates select="@*|node()"/>
        </xsl:element>
      </xsl:when>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="@*">
    <xsl:attribute name="{node-name(.)}">
      <xsl:value-of select="."/>
    </xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

Может кто-нибудь помочь? Пространства имен сложны :(

P.S.: Кто редактировал мою запись: Спасибо :)


person Wickermoon    schedule 22.10.2009    source источник


Ответы (4)


Вы можете установить пространство имен для выходного элемента с помощью атрибута namespace:

<xsl:element name="{node-name(.)}" namespace="http://www.bar.org">
  // ...
</xsl:element>

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

Вот ссылка на отличный учебник по ZVON, в котором приведены рабочие примеры: http://www.zvon.org/xxl/XSLTreference/Output/xslt_element_namespace.html

Я согласен, что пространства имен сложны. Как вы знаете, префикс семантически не имеет значения, но многие системы позволяют вам выбирать префикс из эстетических соображений. Также обратите внимание на Saxon (http://saxon.sourceforge.net/)

EDIT Я думаю, вы найдете свой ответ здесь: пространство имен корневого тега XSLT вместо пространства имен атрибутов элемента

person peter.murray.rust    schedule 22.10.2009
comment
Вы можете сохранить URI в <xsl:variable/> и использовать его как namespace="{$uri}". Это очень хорошо, если вам это нужно чаще. - person Boldewyn; 22.10.2009
comment
Если я прав, то это тоже приведет к тому же XML, имеющему пространства имен в тегах, использующих эти пространства имен, верно? - person Wickermoon; 22.10.2009
comment
Спасибо тысячу раз! Эта ссылка действительно помогла мне, теперь она работает, ура! знак равно - person Wickermoon; 23.10.2009

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:ns1_src="some.url.01"
  xmlns:ns2_src="some.other.url"
  xmlns:ns3_src="another.one"
  xmlns="some.url.02"
  xmlns:ns2="some.other.url.02"
  xmlns:ns3="another.one.02"
>
  <!-- 
    Note that all the source namespaces got their own new "*_src" prefix. 
    The target namespaces take over the original prefixes. 
    "some.url.02" is the new global namespace.
  -->

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

  <!-- the identity template to copy everything, unless 
       it has been declared otherwise -->
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

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

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

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

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

  <xsl:template match="@ns2_src:*">
    <xsl:attribute name="ns2:{local-name()}">
      <xsl:value-of select="." />
    </xsl:attribute>
  </xsl:template>

  <xsl:template match="@ns3_src:*">
    <xsl:attribute name="ns3:{local-name()}">
      <xsl:value-of select="." />
    </xsl:attribute>
  </xsl:template>

  <!-- timestamps will be ignored -->
  <xsl:template match="ns1_src:timestamp" />

</xsl:stylesheet>

Выход:

<order xmlns="some.url.02">
  <orderEntry>
    <orderControl>
      <mandant>test</mandant>
      <businessUnit>test</businessUnit>
      <inboundChannel>test</inboundChannel>
      <requestedDocuments>
        <ns2:document xmlns:ns2="some.other.url.02">orderForm</ns2:document>
      </requestedDocuments>
    </orderControl>
  </orderEntry>
</order>
person Tomalak    schedule 22.10.2009
comment
Спасибо за помощь, но я думаю, что недостаточно ясно объяснил это, поэтому попробуйте еще раз: результат, который вы мне дали, - это то, что я получаю, но я хочу, чтобы объявление xmlns: ns2 было в теге заказа . знак равно - person Wickermoon; 22.10.2009
comment
@Wickermoon - новая ссылка в моем ответе может вам помочь - person peter.murray.rust; 22.10.2009

<xsl:template match="a:*">
  <xsl:element name="{local-name()}"
               namespace="http://example.com/B">
    <xsl:copy-of select="@*" />
    <xsl:apply-templates />
  </xsl:element>
</xsl:template>

Он ищет любой элемент в пространстве имен с префиксом a и заменяет его элементом с тем же именем пространства имен http://example.com/B. Все атрибуты копируются «как есть», а затем оцениваются все дочерние элементы.

Добавьте свою пользовательскую обработку в или вокруг этого по мере необходимости.

person Boldewyn    schedule 22.10.2009
comment
@Boldewyn - вам не нужно использовать шаблон значения атрибута {...} для имени? - person peter.murray.rust; 22.10.2009
comment
К сожалению, когда я добавляю это в свой XSLT, он создает точно такой же xml, как и раньше, имея пространства имен в каждом элементе с этим пространством имен, вместо того, чтобы пространства имен объявлялись один раз в корневом элементе (порядок в этом случае). знак равно - person Wickermoon; 22.10.2009
comment
@peter.murray.rust: о, да, ты прав. Извините, Wickermoon, я обновлю свой ответ через секунду. - person Boldewyn; 22.10.2009
comment
@Wickermoon: Хорошо, теперь он делает то, что рекламирует. Возьмите элементы пространства имен A в качестве входных и выходных синонимичных элементов в пространстве имен B. - person Boldewyn; 22.10.2009
comment
Кстати: на этот раз я протестировал его в Saxon 9.something. - person Boldewyn; 22.10.2009

Используете ли вы XSLT-задачу Ant для преобразования?

Если ответ «да», возможно, вы захотите перейти с механизма XSLT по умолчанию, который поставляется с Sun JDK 1.5+. Прочтите это.

Также прочтите эту статью о пространствах имен в XSLT.

person Alexander Pogrebnyak    schedule 22.10.2009
comment
Спасибо за ссылки, но нет, на самом деле я использую java и Saxon9.something для преобразования. :) - person Wickermoon; 23.10.2009