2009-12-04 9 views
12

Ok, j'ai vu de nombreuses variations sur cette question, mais aucune ne répond exactement à ce que j'essaie de résoudre et peut-être Je suis trop dense pour voir comment appliquer l'une des autres réponses à ce que j'essaie de faire.Comment éliminer les xmlns = "" entrées produites par transformation XSLT d'un document XML en un autre document XML

J'ai quelques XML qui ressemble à quelque chose comme ce qui suit:

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

Maintenant, j'ai une transformation XSLT que je demande à ce XML. Le XSLT est similaire à ce qui suit:

<?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 sortie que je reçois est essentiellement ce que je veux et ressemble à ce qui suit:

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

Mais ce que je ne veux pas sont les xmlns = » " attributs dans le <messageHeader> et <messageBody> éléments.

Maintenant, j'ai trouvé que si je spécifie explicitement l'espace de noms dans le XSLT pour ces éléments, alors l'attribut non désiré est poussé vers le bas d'un niveau pour les enfants de ces attributs.

je pouvais passer par mon XSLT entier et ajouter explicitement les xmlns = « » http://www.companyname.com/schemas/product/Version001 " attribut à chacun de mes xsl:. Élément définitions, mais je sais qu'il doit y avoir une Nous façon plus élégante programmeurs Je suis trop paresseux pour n'avoir pas de raccourci pour ce genre de non-sens.Si mon XSLT ne consistait pas en quelque chose d'aussi simple que l'exemple raccourci, je serais tenté de le faire de cette façon.Mais je sais qu'il doit y avoir un meilleur moyen.

Est-ce que quelqu'un sait ce que je suis absent ici?

Merci,

AlarmTripper

Répondre

8

Utilisez exclude-result-prefixes sur le xsl: tag stylesheet avec le préfixe "#default"

La référence en w3c pour cela est HERE

EDIT: OK, je devrais avoir étudié votre XSL plus attentivement. Déplacez les xmlns sur l'étiquette de message jusqu'à l'étiquette de feuille de style. Cela placera TOUS les éléments de résultat dans le même espace de noms et aboutira à un attribut d'espace de nom sur l'étiquette de message. J'ai couru ceci dans Oxygen/XML et ai obtenu la sortie que vous voulez.

+0

N'a pas modifié le fichier XML de sortie. – AlarmTripper

+0

Quel processeur XSLT utilisez-vous? –

+0

Oui, j'ai confirmé que votre nouvelle suggestion fonctionne également et est probablement une meilleure solution que la mienne car elle maintient l'assignation xmlns dans l'élément de la feuille de style. Et l'option #default m'empêche d'avoir à exclure chacun des autres préfixes d'espace de noms. Merci beaucoup. J'ai beaucoup à apprendre sur ce truc XSLT et je pense que les espaces de noms sont probablement l'un des aspects les plus complexes. – AlarmTripper

0

Ok, je l'ai compris.

Le XSLT Je veux ressemble à ceci:

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

Le changement qui fixe était d'ajouter les exclude-result-prefixes attribut à la < xsl: stylesheet > élément et de modifier l'article qui était:

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

être les suivants à la place:

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

Et maintenant je suis heureux à nouveau.

Il y a probablement de meilleures façons de le faire, mais cela fonctionne pour moi. Toutes les suggestions futures sont toujours les bienvenues.

0

La réponse de Jim Garrison (mise à jour) est tout ce dont vous auriez dû avoir besoin. Mais la feuille de style mise à jour que vous avez publiée génère un attribut "namespace" dans le résultat, donc je ne suis pas sûr de ce que cela vous fait de bien.

L'élément clé à comprendre est le fonctionnement de l'espace de noms par défaut. Ne considérez pas xmlns comme un attribut que vous pouvez afficher dans le résultat. Au lieu de cela, pensez-y comme un détail lexical de votre feuille de style, dont le but est de définir l'espace de noms par défaut pour tout ce qui se trouve en dessous (l'élément lui-même et chacun de ses descendants). (À son tour, il a la même fonction dans le résultat XML, qui a une structure très différente de la feuille de style elle-même.)

Eléments de résultat littéraux dans votre feuille de style (par exemple, < message>) ainsi que < xsl: élément > instructions (par exemple, < xsl: element name = "message">) prennent l'espace de nom par défaut lorsque le nom fourni n'utilise pas de préfixe. Si vous voulez tous les d'entre eux pour prendre ce même espace de noms, alors vous devrez mettre un espace de noms par défaut en haut de votre feuille de style, comme Jim Garrison l'a suggéré. Sinon, vous finirez avec certains éléments qui ne sont pas dans cet espace de noms, ce qui explique pourquoi le résultat contient xmlns = "" (désactivant l'espace de noms pour ces éléments).

+0

Merci Evan! J'apprécie toute l'aide que je peux obtenir ici. J'ai lu que 'xmlns' ressemble à un attribut, mais ce n'est pas le cas. Je suis retourné et j'ai changé le code pour qu'il corresponde à ce que Jim a suggéré et ajouté un qualificatif d'espace de noms (terminologie?) Pour que ma balise namespace soit maintenant dans ma définition de 'stylesheet' et ressemble à 'xmlns: grf = "http: //www.blahblah.com "et puis est retourné à travers pour être sûr que mes éléments sont préfixés avec" grf: " L'aide de vos experts sur ici pour être inestimable depuis personne d'autre autour de mon entreprise a fait beaucoup avec XSLT ou XPATH. J'apprécie vraiment l'apprendre bien! – AlarmTripper

Questions connexes