2011-06-17 1 views
2

J'ai des documents xml qui suivent un schéma où la plupart des éléments définis sont autorisés à être la racine d'une instance valide. J'ai aussi plusieurs v2.0 de xslt qui le traduisent de différentes manières (le mettre dans une forme normale, une forme compacte, un dialecte différent, ...) Ces xslt sont tous basés sur une transformation d'identité avec des templates ajoutés pour faire le désiré modification. Le problème est qu'il existe une prolifération d'attributs d'espace de noms car certains éléments proviennent de l'extérieur de l'espace de noms par défaut.xslt: conserver la déclaration d'espace de nom à la racine lorsque l'élément racine n'est pas connu à l'avance

J'ai essayé les procédures recommandées pour insérer l'espace de noms sur l'élément racine, mais je n'arrive pas à le faire correctement. Les problèmes sont: 1. la transformation peut changer le nom, et parfois le contenu de l'élément racine, donc j'ai toujours besoin des modèles pour chacun des éléments globaux, et puisque je ne sais pas lequel sera racine, je ne peut pas insérer des éléments d'espace de nommage si nécessaire (je ne sais pas où ils seront nécessaires pour un document particulier 2. J'ai pensé mettre en œuvre ceci comme multi-pass, ou simplement comme un xslt indépendant, puisque je veux le même résultat Dans ce cas, ce dont j'aurais besoin est une transformation d'identité qui prend tous les espaces de noms et les préfixes de tous les éléments du document, et les insère dans la racine, ce qui, je l'espère, supprimera automatiquement les attributs les enfants? Cependant, j'ai essayé le suivant

<?xml version="1.0" ?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:strip-space elements="*"/> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template name="start" match="/"> 
     <xsl:copy> 
      <xsl:for-each select="*"> 
       <xsl:copy> 
        <xsl:for-each select="descendant::*"> 
         <xsl:call-template name="add-ns"> 
          <xsl:with-param name="ns-namespace"> 
           <xsl:value-of select="namespace-uri()"/> 
          </xsl:with-param> 
          <xsl:with-param name="ns-prefix"> 
           <xsl:value-of 
            select=" prefix-from-QName(QName(namespace-uri(),name()))"/> 
          </xsl:with-param> 
         </xsl:call-template> 
        </xsl:for-each> 
        <xsl:apply-templates select="node() | @*"/> 
       </xsl:copy> 
      </xsl:for-each> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template name="add-ns"> 
     <xsl:param name="ns-prefix" select="'x'"/> 
     <xsl:param name="ns-namespace" select="'someNamespace'"/> 
     <xsl:namespace name="{$ns-prefix}" select="$ns-namespace"/> 
    </xsl:template> 
    <xsl:template match="node()|@* "> 
     <xsl:copy> 
      <xsl:apply-templates select="node() | @*"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

Et cela fonctionne pour tous les préfixes qui apparaissent sur les éléments, mais il n'attrape pas les préfixes des attributs. Voici un document de test:

<RuleML xmlns="http://www.ruleml.org/0.91/xsd"> 
    <Assert textiri="xy&gt;z"> 
     <Importation xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="abc" 
        textiri="urn:common-logic:demo1" 
        xlink:href="http://common-logic.org/x&gt;cl/demos.xml"/> 
     <a:anything xmlns:a="http://anything.org" 
        xmlns:xlink="http://www.w3.org/1999/xlink"/> 
    </Assert> 
</RuleML> 

Je veux produire:

<RuleML xmlns="http://www.ruleml.org/0.91/xsd" xmlns:a="http://anything.org" xmlns:xlink="http://www.w3.org/1999/xlink" > 
    <Assert textiri="xy&gt;z"> 
     <Importation xml:id="abc" 
        textiri="urn:common-logic:demo1" 
        xlink:href="http://common-logic.org/x&gt;cl/demos.xml"/> 
     <a:anything/> 
    </Assert> 
</RuleML> 

mais je reçois

<RuleML xmlns="http://www.ruleml.org/0.91/xsd" xmlns:a="http://anything.org"> 
    <Assert textiri="xy&gt;z"> 
     <Importation xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="abc" 
        textiri="urn:common-logic:demo1" 
        xlink:href="http://common-logic.org/x&gt;cl/demos.xml"/> 
     <a:anything xmlns:xlink="http://www.w3.org/1999/xlink"/> 
    </Assert> 
</RuleML> 

Tara

Répondre

3

Est-ce que ce qui suit faire ce que vous voulez?

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs"> 

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

    <xsl:template match="/*"> 
    <xsl:copy> 
     <xsl:copy-of select="descendant::*/namespace::*"/> 
     <xsl:apply-templates select="@* , node()"/> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

Avec Saxon 9.3, il semble faire le travail sur l'échantillon que vous avez posté. Je ne suis cependant pas sûr de ce que vous voulez faire s'il y a plusieurs éléments dans différents espaces de noms par défaut ou plusieurs éléments dans des espaces de noms différents mais en utilisant le même préfixe. Par exemple, avec

<root xmlns="http://example.com/ns1"> 
    <foo xmlns="http://example.com/ns2"> 
    <pf:bar xmlns:pf="http://example.com/ns3"> 
     <pf:foobar xmlns:pf="http://example.com/ns4"/> 
    </pf:bar> 
    </foo> 
</root> 

saxon signale simplement l'erreur

Error at xsl:copy-of on line 15 of test2011061801Xsl2.xsl: 
    XTDE0430: Cannot create two namespace nodes with the same prefix mapped to different URIs 
    (prefix="", URI=http://example.com/ns2, URI=http://example.com/ns1) 
    in built-in template rule 

[modifier] Si vous ne voulez pas d'une erreur à signaler que vous pourriez essayer de mettre en œuvre une stratégie pour tirer des espaces de noms comme le plus loin possible, mais pour éviter toute collision. Cela peut se faire avec de-chaque groupe, comme dans l'exemple suivant XSLT 2.0:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs"> 

    <xsl:template match="@* | text() | processing-instruction() | comment()"> 
    <xsl:copy/> 
    </xsl:template> 

    <xsl:template match="*"> 
    <xsl:copy copy-namespaces="no"> 
     <xsl:for-each-group select="descendant-or-self::*/namespace::*" group-by="local-name()"> 
     <xsl:copy-of select="."/> 
     </xsl:for-each-group> 
     <xsl:apply-templates select="@* , node()"/> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

Avec l'entrée étant

<root xmlns="http://example.com/ns1"> 
    <foo xmlns="http://example.com/ns2"> 
    <pf:bar xmlns:pf="http://example.com/ns3"> 
     <pf:foobar xmlns:pf="http://example.com/ns4"/> 
    </pf:bar> 
    </foo> 
</root> 

Saxon 9.3 sorties

<?xml version="1.0" encoding="UTF-8"?><root xmlns="http://example.com/ns1" xmlns:pf="http://example.com/ns3"> 
    <foo xmlns="http://example.com/ns2"> 
    <pf:bar> 
     <pf:foobar xmlns:pf="http://example.com/ns4"/> 
    </pf:bar> 
    </foo> 
</root> 
0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:strip-space elements="*"/> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template match="*:RuleML"> 
     <xsl:copy> 
     <xsl:for-each select="descendant::node()"> 
      <xsl:choose> 
       <xsl:when test="self::text()"/> 

       <xsl:otherwise> 
        <xsl:for-each select="namespace::node()"> 
         <xsl:copy-of select="."/> 
        </xsl:for-each>   
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:for-each> 
      <xsl:apply-templates select="(node() | @*) except namespace::node()"/> 
     </xsl:copy> 
    </xsl:template> 

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