2009-12-04 13 views
12

Ok, he visto numerosas variaciones en esta pregunta, pero ninguna responde exactamente a lo que trato de resolver y tal vez ' Estoy demasiado densa para ver cómo aplicar una de las otras respuestas a lo que estoy tratando de hacer.Cómo eliminar las entradas xmlns = "" producidas por la transformación XSLT de un documento XML en otro documento XML

que tienen algún XML que se ve algo como lo siguiente:

<?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> 

Ahora tengo una transformación XSLT que estoy aplicando a este XML. El XSLT es similar al siguiente:

<?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> 

La salida que se ve es básicamente lo que quiero y tiene el siguiente aspecto:

<?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> 

Pero lo que no quiero son los xmlns =" " atributos en el <messageHeader> y <messageBody> elementos.

Ahora he encontrado que si especifico explícitamente el espacio de nombres en el XSLT para esos elementos, entonces el atributo no deseado se empuja un nivel hacia abajo a los elementos secundarios de esos atributos.

tan sólo pudiera ir a través de toda mi XSLT y explícitamente agregar los xmlns = "" http://www.companyname.com/schemas/product/Version001 " atributo para cada uno de mis XSL:. Elemento definiciones, pero sé que tiene que haber una forma más elegante Nosotros los programadores son demasiado perezosos para no tener un atajo para este tipo de tonterías. Si mi XSLT no consistía en algo tan simple como el ejemplo abreviado, me siento tentado a hacerlo de esa manera. Pero sé que debe haber una manera mejor.

¿alguien sabe lo que me falta aquí?

Gracias,

AlarmTripper

Respuesta

8

Uso excluir-result-prefijos en la etiqueta xsl: hoja de estilos con el prefijo "#default"

La referencia en el W3C para esto es HERE

EDIT: OK, debería haber estudió su XSL con más cuidado. Mueva los xmlns en la etiqueta del mensaje hasta la etiqueta de la hoja de estilo. Esto colocará TODOS los elementos de resultado en el mismo espacio de nombres y dará como resultado un atributo de espacio de nombres en la etiqueta de mensaje. Ejecuté esto en Oxygen/XML y obtuve el resultado que deseaba.

+0

no cambió el XML de salida. – AlarmTripper

+0

¿Qué procesador XSLT estás usando? –

+0

Sí, confirmó que su nueva sugerencia también funciona y es probablemente una solución mejor que la mía, ya que mantiene la asignación de xmlns en el elemento de la hoja de estilo. Y la opción #default me ​​impide tener que excluir cada uno de los otros prefijos del espacio de nombres. Muchas gracias. Tengo mucho que aprender sobre este material XSLT y creo que los espacios de nombres son probablemente uno de los aspectos más complicados. – AlarmTripper

0

Ok, lo descubrí.

El XSLT que quiero es así:

<?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> 

El cambio que fija era añadir las excluir-result-prefijos atributo a la < xsl: stylesheet > elemento y para cambiar la sección que era:

<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> 

para ser el siguiente en su lugar:

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

y ahora estoy feliz de nuevo.

probablemente hay mejores maneras de hacerlo, pero esto es trabajo para mí. Cualquier sugerencia futura es bienvenida.

0

(actualizado) La respuesta de Jim Garrison es todo lo que debería haber necesitado. Pero la hoja de estilo actualizada que publicó arroja un atributo de "espacio de nombres" en el resultado, así que no estoy seguro de qué tan bueno sea eso.

La clave es entender cómo funciona el espacio de nombres predeterminado. No piense en xmlns como un atributo que puede mostrar en el resultado. En su lugar, piense en ello como un detalle léxico de su hoja de estilo, cuyo propósito es establecer el espacio de nombre predeterminado para todo lo que está debajo de él (el elemento en sí y cada uno de sus descendientes hasta que se anule). (A su vez, tiene la misma función en el resultado XML, que tiene una estructura muy diferente a la hoja de estilo en sí).

Elementos de resultados literales en su hoja de estilo (por ejemplo, < mensaje>) así como < xsl: elemento > las instrucciones (p. ej., < xsl: nombre del elemento = "mensaje">) adoptan el espacio de nombres predeterminado cuando el nombre suministrado no usa un prefijo. Si quieres todo de ellos para asumir ese mismo espacio de nombres, entonces tendrá que poner un nombre por defecto en la parte superior de la hoja de estilos, como se sugiere Jim Garrison.

De lo contrario, va a terminar con algunos elementos que no están en ese espacio de nombres, por lo que el resultado contenía xmlns = "" (desconexión del espacio de nombres para estos elementos).

+0

Gracias Evan! Agradezco toda la ayuda que puedo obtener aquí. Leí que 'xmlns' parece un attrib, pero no lo es. Regresé y cambié el código para que coincidiera con lo sugerido por Jim y agregué un calificador de espacio de nombres (terminología) para que mi etiqueta de espacio de nombres esté ahora en mi definición de 'hoja de estilos' y se vea como 'xmlns: grf =' http: //www.blahblah.com "y luego volvió para asegurarse de que mis elementos tengan el prefijo" grf: ". La ayuda de sus expertos aquí es invaluable ya que nadie más en mi empresa ha hecho mucho con XSLT o XPATH. ¡Estoy realmente disfrutando aprendiéndolo! – AlarmTripper

Cuestiones relacionadas