2016-11-30 1 views
0

Je suis en train de compiler une transformation XSLT en utilisant XSLTC, mais la classe résultante n'est pas utilisable, car il contient des méthodes avec des noms illégaux.XSLTC créer des classes avec des noms de méthodes illégales

À titre d'illustration, voici une version (simplifiée) de la feuille de style que j'utilise:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ns1="http://some.weird/Namespace#/Definition" 
    xmlns="http://another.strange/Namespace#/Definition"> 

    <xsl:template match="ns1:*"> 
     <xsl:element name="{local-name()}"> 
      <xsl:apply-templates /> 
     </xsl:element> 
    </xsl:template> 

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

    <xsl:template match="text()"> 
     <xsl:value-of select="." /> 
    </xsl:template> 
</xsl:stylesheet> 

Ce que cela tente d'accomplir est de changer l'espace de noms de tous les éléments d'un fichier XML à un autre un, donc je suis fondamentalement en utilisant une transformation d'identité modifiée. Cependant, XSLTC semble avoir un problème avec les caractères '#' dans les URI de l'espace de noms (même si pour autant que je sache, ils devraient être légaux). Parce que le fichier de classe qui XSLTC crée lors de la compilation l'aspect ci-dessus comme celui-ci (décompilé, bien sûr):

import org.apache.xalan.xsltc.DOM; 
import org.apache.xalan.xsltc.TransletException; 
import org.apache.xalan.xsltc.dom.UnionIterator; 
import org.apache.xalan.xsltc.runtime.AbstractTranslet; 
import org.apache.xalan.xsltc.runtime.BasisLibrary; 
import org.apache.xml.dtm.DTMAxisIterator; 
import org.apache.xml.serializer.SerializationHandler; 

public class ChangeNamespace extends AbstractTranslet { 
    public DOM _dom; 
    protected static String[] _sNamesArray = new String[0]; 
    protected static String[] _sUrisArray = new String[0]; 
    protected static int[] _sTypesArray = new int[0]; 
    protected static String[] _sNamespaceArray = new String[0]; 

    public void buildKeys(DOM var1, DTMAxisIterator var2, SerializationHandler var3, int var4) throws TransletException { 
    } 

    public void topLevel(DOM var1, DTMAxisIterator var2, SerializationHandler var3) throws TransletException { 
     boolean var4 = false; 
    } 

    public void transform(DOM var1, DTMAxisIterator var2, SerializationHandler var3) throws TransletException { 
     this._dom = this.makeDOMAdapter(var1); 
     boolean var4 = false; 
     this.transferOutputSettings(var3); 
     this.buildKeys(this._dom, var2, var3, 0); 
     this.topLevel(this._dom, var2, var3); 
     var3.startDocument(); 
     this.applyTemplates(this._dom, var2, var3); 
     var3.endDocument(); 
    } 

    public void http$colon$$slash$$slash$another$dot$strange$slash$Namespace#$slash$Definition$colon$template$dot$0(DOM var1, DTMAxisIterator var2, SerializationHandler var3, int var4) { 
     String var5 = BasisLibrary.getLocalName(var1.getNodeName(var4)); 
     BasisLibrary.checkQName(var5); 
     String var10001 = BasisLibrary.startXslElement(var5, (String)null, var3, var1, var4); 
     this.applyTemplates(var1, var1.getChildren(var4), var3); 
     var3.endElement(var10001); 
    } 

    public void http$colon$$slash$$slash$another$dot$strange$slash$Namespace#$slash$Definition$colon$template$dot$1(DOM var1, DTMAxisIterator var2, SerializationHandler var3, int var4) { 
     String var5; 
     if((var5 = var1.shallowCopy(var4, var3)) != null) { 
      int var6 = var5.length(); 
      this.applyTemplates(var1, (new UnionIterator(var1)).addIterator(var1.getAxisIterator(2)).addIterator(var1.getAxisIterator(3)).setStartNode(var4), var3); 
      if(var6 != 0) { 
       var3.endElement(var5); 
      } 
     } 

    } 

    public void http$colon$$slash$$slash$another$dot$strange$slash$Namespace#$slash$Definition$colon$template$dot$2(DOM var1, DTMAxisIterator var2, SerializationHandler var3, int var4) { 
     var1.characters(var4, var3); 
    } 

    public final void applyTemplates(DOM var1, DTMAxisIterator var2, SerializationHandler var3) throws TransletException { 
     int var4; 
     while((var4 = var2.next()) >= 0) { 
      switch(var1.getExpandedTypeID(var4)) { 
      case 0: 
      case 9: 
       this.applyTemplates(var1, var1.getChildren(var4), var3); 
       break; 
      case 1: 
       if(var1.getNamespaceName(var4).equals("http://some.weird/Namespace#/Definition")) { 
        this.http$colon$$slash$$slash$another$dot$strange$slash$Namespace#$slash$Definition$colon$template$dot$0(var1, var2, var3, var4); 
        break; 
       } else { 
        var4 = var4; 
       } 
      case 2: 
      case 7: 
      case 8: 
       this.http$colon$$slash$$slash$another$dot$strange$slash$Namespace#$slash$Definition$colon$template$dot$1(var1, var2, var3, var4); 
       break; 
      case 3: 
       this.http$colon$$slash$$slash$another$dot$strange$slash$Namespace#$slash$Definition$colon$template$dot$2(var1, var2, var3, var4); 
      case 4: 
      case 5: 
      case 6: 
      case 10: 
      case 11: 
      case 12: 
      case 13: 
      } 
     } 

    } 

    public ChangeNamespace() { 
     super.namesArray = _sNamesArray; 
     super.urisArray = _sUrisArray; 
     super.typesArray = _sTypesArray; 
     super.namespaceArray = _sNamespaceArray; 
     super.transletVersion = 101; 
    } 
} 

Notez le « # » dans certains des noms de méthode générés, ce qui est illégal selon la spécification Java, et il n'est pas surprenant que cela donne une classe ClassFormatException du classloader lorsque j'essaie réellement d'utiliser la classe.

Des idées si je peux en quelque sorte obtenir XSLTC pour compiler le XSL en quelque chose de valide? Est-ce que je peux peut-être modifier ma feuille de style pour accomplir la même chose qui ne cause pas ce problème?

Et non, je ne peux pas changer les namespaces eux-mêmes, ils sont fixés parce qu'ils appartiennent à un système externe que je dois traiter, mais n'a aucune influence sur.

+0

Vous pourriez probablement la carte l'espace de nom bizarre (avec la barre oblique dans le fragment) à un URI plus raisonnable lors de l'analyse de l'entrée XSL et XML. – aventurin

Répondre

0

En étudiant le problème plus loin par débogage dans le code de XSLTC, j'ai réussi à réduire la cause à un appel à une méthode nommée escape dans la classe org.apache.xalan.xsltc.compiler.util.Util.

C'est à quoi il ressemble dans le code source (Xalan 2.7.2):

public static String escape(String input) { 
    return replace(input, ".-/:", new String[]{"$dot$", "$dash$", "$slash$", "$colon$"}); 
} 

Il est appelé à partir de plusieurs endroits en essayant de créer des noms de méthode à partir de chaînes (comme, dans mon cas, namespaces), bien que cette mise en œuvre naïve soit scandaleusement insuffisante à cet effet, comme le démontre mon cas. La chaîne renvoyée est utilisée sans autre modification ou vérification pour s'assurer que le nom résultant est réellement valide en Java.

Ma solution (que je ne entrer dans les détails ici, parce que ce n'est pas une bonne solution - il n'est pas pour les timorés et ceux qui essaient de faire la même chose devrait avoir suffisamment savoir- comment répliquer sans instruction supplémentaire, ou rester loin de cette supercherie), était d'utiliser effectivement la manipulation de bytecode pour remplacer le corps de la méthode ci-dessus avec quelque chose qui gère également les caractères « de # ». C'est un mouvement désespéré, mais qui fonctionne pour moi, au moins pour l'instant.