2016-11-30 4 views
0

Я пытаюсь скомпилировать преобразование XSLT с помощью XSLTC, но полученный класс не может быть использован, поскольку он содержит методы с незаконными именами.XSLTC, создающий классы с незаконными именами методов

В целях иллюстрации, здесь (упрощенный) вариант таблицы стилей я использую:

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

Что это пытается добиться, чтобы изменить пространство имен всех элементов файла XML в другой один, поэтому я в основном использую модифицированное преобразование идентичности. Однако XSLTC, похоже, имеет проблемы с символами «#» в URI пространства имен (хотя, насколько я понимаю, они должны быть законными). Поскольку файл класс, который XSLTC создает при компиляции выше выглядит следующим образом (декомпилировано, конечно):

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

Обратите внимание на «#» в некоторых из сгенерированных имен методов, что является незаконным в соответствии со спецификацией Java, и не удивительно, что это приводит к исключению ClassFormatException, предоставляемому загрузчиком классов, когда я действительно пытаюсь использовать класс.

Любые идеи, если я могу каким-то образом заставить XSLTC скомпилировать XSL во что-то действующее? Могу ли я каким-либо образом изменить мою таблицу стилей, чтобы выполнить то же самое, что не вызывает этой проблемы?

И нет, я не могу изменить сами пространства имен, они исправлены, потому что они принадлежат к внешней системе, с которой мне приходится иметь дело, но не имеют никакого влияния.

+0

Возможно, вы можете сопоставить странное пространство имен (с косой чертой в фрагменте) с более разумным URI при анализе входных данных XSL и XML. – aventurin

ответ

0

Дальнейшее исследование проблемы путем отладки в код XSLTC, мне удалось сузить причину до вызова метода с именем escape в классе org.apache.xalan.xsltc.compiler.util.Util.

Это то, что это выглядит как в самом исходном коде (Xalan 2.7.2):

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

Он вызывается из нескольких мест, при попытке создать имена методов из строк (как в моем случае, пространства имен), хотя эта наивная реализация для этой цели является ужасно недостаточной, о чем свидетельствует мое дело. Возвращаемая строка используется без каких-либо дальнейших модификаций или проверок, чтобы гарантировать, что результирующее имя действительно действительно на Java.

Мое решение (которое я буду не вдаваться в подробности здесь, потому что это не хорошее решение - это не для слабонервных, и кто пытается сделать то же самое должно иметь достаточно ноу как реплицировать его без дополнительной инструкции или держаться подальше от такого обмана), было фактически использовать манипуляцию байт-кодом, чтобы заменить тело вышеописанного метода тем, что также обрабатывает символы «#». Это отчаянный ход, но тот, который работает для меня, по крайней мере на данный момент.

Смежные вопросы