Невозможно добавить префикс пространства имен для детей, использующих XSL - PullRequest
7 голосов
/ 04 июня 2010

Я проверил много ответов здесь, и я думаю, что я почти там. Одна вещь, которая беспокоит меня (и по какой-то причине это требует мой сверстник):

У меня есть следующий входной XML:

<?xml version="1.0" encoding="utf-8"?>
<MyRoot>
  <MyRequest CompletionCode="0" CustomerID="9999999999"/>
  <List TotalList="1">
    <Order CustomerID="999999999" OrderNo="0000000001" Status="Shipped">
      <BillToAddress ZipCode="22221"/>
      <ShipToAddress ZipCode="22222"/>
      <Totals Tax="0.50" SubTotal="10.00" Shipping="4.95"/>
    </Order>
  </List>
  <Errors/>
</MyRoot>

Меня попросили произвести это:

<ns:MyNewRoot xmlns:ns="http://schemas.foo.com/response"  
xmlns:N1="http://schemas.foo.com/request"  
xmlns:N2="http://schemas.foo.com/details">
    <N1:MyRequest CompletionCode="0" CustomerID="9999999999"/>
    <ns:List TotalList="1">
            <N2:Order CustomerID="999999999" Level="Preferred" Status="Shipped">
                    <N2:BillToAddress ZipCode="22221"/>
                    <N2:ShipToAddress ZipCode="22222"/>
                    <N2:Totals Tax="0.50" SubTotal="10.00" Shipping="4.95"/>
            </N2:Order>
    </ns:List>
    <ns:Errors/>
</ns:MyNewRoot>

Обратите внимание, что дочерним элементам N2: Order также требуется префикс N2: и префикс ns: для остальных элементов.

Я использую XSL-преобразование ниже:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

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


<xsl:template match="/MyRoot">
 <MyNewRoot xmlns="http://schemas.foo.com/response"
   xmlns:N1="http://schemas.foo.com/request"
   xmlns:N2="http://schemas.foo.com/details">
     <xsl:apply-templates/>
 </MyNewRoot>
 </xsl:template>

<xsl:template match="/MyRoot/MyRequest">
  <xsl:element name="N1:{name()}" namespace="http://schemas.foo.com/request">
    <xsl:copy-of select="namespace::*"/>
    <xsl:apply-templates select="@* | node()"/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="/MyRoot/List/Order">
  <xsl:element name="N2:{name()}" namespace="http://schemas.foo.com/details">
    <xsl:copy-of select="namespace::*"/>
    <xsl:apply-templates select="@* | node()"/>
  </xsl:element>
 </xsl:template>

</xsl:stylesheet>

Этот не обрабатывает ns (я не мог понять это). Когда я обрабатываю вышеупомянутое XSL-преобразование с AltovaXML, я получаю следующее:

<MyNewRoot xmlns="http://schemas.foo.com/response"  
xmlns:N1="http://schemas.foo.com/request"  
xmlns:N2="http://schemas.foo.com/details">
    <N1:MyRequest CompletionCode="0" CustomerID="9999999999"/>
    <List xmlns="" TotalList="1">
            <N2:Order CustomerID="999999999" Level="Preferred" Status="Shipped">
                    <BillToAddress ZipCode="22221"/>
                    <ShipToAddress ZipCode="22222"/>
                    <Totals Tax="0.50" SubTotal="10.00" Shipping="4.95"/>
            </N2:Order>
    </List>
    <Errors/>
</MyNewRoot>

Обратите внимание, что префикс N2: для потомков Порядка не существует после преобразования XSL. Также дополнительные xmlns = "" в заголовке заказа (по некоторым причинам). Я не мог понять, как поставить префикс ns: для остальных элементов (таких как Errors и List).

Прежде всего, зачем мне ставить префикс для детей, если он уже есть у родителей. Разве родительское пространство имен не определяет дочерние узлы / пространства имен атрибутов?

Во-вторых, я хочу добавить префиксы в приведенный выше XML, как ожидается, как я могу сделать это с XSL?

Ответы [ 2 ]

7 голосов
/ 05 июня 2010

Это преобразование (всего 42 строки) :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ns="http://schemas.foo.com/response"
 xmlns:N1="http://schemas.foo.com/request"
 xmlns:N2="http://schemas.foo.com/details"
 >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="*">
  <xsl:element name="ns:{name()}"
       namespace="http://schemas.foo.com/response">
    <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="@*">
   <xsl:copy-of select="."/>
 </xsl:template>

 <xsl:template match="/MyRoot">
  <xsl:element name="ns:{name()}"
       namespace="http://schemas.foo.com/response">
    <xsl:copy-of select=
     "document('')/*/namespace::*[name()='N1' or name()='N2']"/>
    <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="MyRequest">
  <xsl:element name="N1:{name()}"
       namespace="http://schemas.foo.com/request">
    <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="*[ancestor-or-self::Order]">
  <xsl:element name="N2:{name()}"
       namespace="http://schemas.foo.com/details">
    <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному документу XML :

<MyRoot>
  <MyRequest CompletionCode="0" CustomerID="9999999999"/>
  <List TotalList="1">
    <Order CustomerID="999999999" OrderNo="0000000001" Status="Shipped">
      <BillToAddress ZipCode="22221"/>
      <ShipToAddress ZipCode="22222"/>
      <Totals Tax="0.50" SubTotal="10.00" Shipping="4.95"/>
    </Order>
  </List>
  <Errors/>
</MyRoot>

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

<ns:MyRoot xmlns:N1="http://schemas.foo.com/request" xmlns:N2="http://schemas.foo.com/details" xmlns:ns="http://schemas.foo.com/response">
    <N1:MyRequest CompletionCode="0" CustomerID="9999999999"/>
    <ns:List TotalList="1">
        <N2:Order CustomerID="999999999" OrderNo="0000000001" Status="Shipped">
            <N2:BillToAddress ZipCode="22221"/>
            <N2:ShipToAddress ZipCode="22222"/>
            <N2:Totals Tax="0.50" SubTotal="10.00" Shipping="4.95"/>
        </N2:Order>
    </ns:List>
    <ns:Errors/>
</ns:MyRoot>

Примечание :

  1. Использование <xsl:element> и его атрибутов name и namespace.

  2. Как identity template превратился в первые два шаблона преобразования - это решение было основано на том факте, что только в исключительных случаях элемент не должен находиться в пространстве имен ns:. *

  3. Как указывается пространство имен N2: для элемента Order или любого из его потомков.

4 голосов
/ 05 июня 2010

Если вы действительно заботитесь о том, какие префиксы пространства имен находятся в выходных данных, тогда вы захотите использовать элементы литерального результата в своих шаблонах, а не конструктор xsl:element:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ns="http://schemas.foo.com/response"
    xmlns:N1="http://schemas.foo.com/request"  
    xmlns:N2="http://schemas.foo.com/details">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

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

    <xsl:template match="MyRoot">
        <ns:MyNewRoot>
            <xsl:apply-templates/>
        </ns:MyNewRoot>
    </xsl:template>

    <xsl:template match="MyRequest">
        <N1:MyRequest>
            <xsl:apply-templates select="@* | node()"/>
        </N1:MyRequest>
    </xsl:template>

    <xsl:template match="List">
        <ns:List>
            <xsl:apply-templates select="@* | node()"/>
        </ns:List>
    </xsl:template>    

    <xsl:template match="Order">
        <N2:Order>
            <xsl:apply-templates select="@* | node()"/>
        </N2:Order>
    </xsl:template>

    <xsl:template match="BillToAddress">
        <N2:BillToAddress>
            <xsl:apply-templates select="@* | node()"/>
        </N2:BillToAddress>
    </xsl:template>

    <xsl:template match="ShipToAddress">
        <N2:ShipToAddress>
            <xsl:apply-templates select="@* | node()"/>
        </N2:ShipToAddress>
    </xsl:template>

    <xsl:template match="Totals">
        <N2:Totals>
            <xsl:apply-templates select="@* | node()"/>
        </N2:Totals>
    </xsl:template>

    <xsl:template match="Errors" />

</xsl:stylesheet>

Вы должны знать, что пространство имен важно , префикс пространства имен не . Это синтаксический сахар. Вы можете иметь несколько префиксов пространства имен, связанных с одним и тем же пространством имен uri, или не иметь префикса пространства имен и по-прежнему создавать элементы одного типа (связанные с конкретным пространством имен uri).

...