2013-09-05 2 views
3

Я использую javax.xml.transform.* для преобразования XSLT. Поскольку xslt-файл, который будет использоваться, поступает из внешнего мира, в этом файле могут быть ошибки, и я собираюсь вернуть какой-то значимый ответ пользователю.Как извлечь полезную информацию из TransformerException

Хотя я могу легко поймать TransformationException, я не нашел способа получить от него достаточную информацию. Например, если есть тег должен заканчиваться конечным тэгом, printStackTrace() выдает сообщение рубцевания

javax.xml.transform.TransformerConfigurationException: Could not compile stylesheet 
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTemplates(Unknown Source) 
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTransformer(Unknown Source) 
    ... (100 lines) 

и getMessage() дает только

Could not compile stylesheet 

Ни один из них не дает истинную причину ошибки.

Я заметил, что в тестовой консоли Eclipse, я могу увидеть следующее

[Fatal Error] :259:155: The element type "sometag" must be terminated by the matching end-tag "</sometag>". 
ERROR: 'The element type "sometag" must be terminated by the matching end-tag "</sometag>".' 
FATAL ERROR: 'Could not compile stylesheet' 

Это именно то, что я хочу. К сожалению, поскольку это веб-приложение, пользователь не видит этого.

Как я могу отобразить правильное сообщение об ошибке для пользователя?

+0

Вы действительно не можете. Если вы хотите запустить этап проверки ..... – Thihara

+0

Не является причиной причины? – agad

+0

@agad К сожалению, 'getCause()' call возвращает 'null'. –

ответ

1

Поместите свой собственный ErrorListener на вашем Transformer например, с использованием Transformer.setErrorListener, например, так:

final List<TransformationException> errors = new ArrayList<TransformationException>(); 
Transformer transformer = ... ; 
transformer.setErrorListener(new ErrorListener() { 

    @Override 
    public void error(TransformerException exception) { 
     errors.add(exception); 
    } 

    @Override 
    public void fatalError(TransformerException exception) { 
     errors.add(exception); 
    } 

    @Override 
    public void warning(TransformerException exception) { 
     // handle warnings as well if you want them 
    } 
}); 

// Any other transformer setup 

Source xmlSource = ... ; 
Result outputTarget = ... ; 
try { 
    transformer.transform(xmlSource, outputTarget); 
} catch (TransformerException e) { 
    errors.add(e); // Just in case one is thrown that isn't handled 
} 
if (!errors.isEmpty()) { 
    // Handle errors 
} else { 
    // Handle output since there were no errors 
} 

Это будет регистрировать все ошибки, возникающие в errors списке, то вы можете использовать сообщения из этих ошибок, чтобы получить то, что вы хотите. Это имеет дополнительное преимущество, что он попытается возобновить преобразование после возникновения ошибок. Если это вызывает какие-либо проблемы, просто повторно выдать исключение, выполнив:

@Override 
public void error(TransformerException exception) throws TransformationException { 
    errors.add(exception); 
    throw exception; 
} 

@Override 
public void fatalError(TransformerException exception) throws TransformationException { 
    errors.add(exception); 
    throw exception; 
} 
-1

Вы можете настроить System.out написать в собственном OutputStream. Использование ErrorListener не позволяет получить весь вывод. Если вы работаете с нитками, вы можете посмотреть здесь (http://maiaco.com/articles/java/threadOut.php), чтобы избежать изменения System.out для других потоков.

пример

public final class XslUtilities { 
    private XslUtilities() { 
     // only static methods 
    } 

    public static class ConvertWithXslException extends Exception { 
     public ConvertWithXslException(String message, Throwable cause) { 
      super(message, cause); 
     } 
    } 

    public static String convertWithXsl(String input, String xsl) throws ConvertWithXslException { 
     ByteArrayOutputStream systemOutByteArrayOutputStream = new ByteArrayOutputStream(); 
     PrintStream oldSystemOutPrintStream = System.out; 
     System.setOut(new PrintStream(systemOutByteArrayOutputStream)); 

     ByteArrayOutputStream systemErrByteArrayOutputStream = new ByteArrayOutputStream(); 
     PrintStream oldSystemErrPrintStream = System.err; 
     System.setErr(new PrintStream(systemErrByteArrayOutputStream)); 

     String resultXml; 
     try { 
      System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl"); 
      TransformerFactory transformerFactory = TransformerFactory.newInstance(); 
      Transformer transformer = transformerFactory.newTransformer(new StreamSource(new StringReader(xsl))); 
      StringWriter stringWriter = new StringWriter(); 
      transformer.transform(new StreamSource(new StringReader(input)), new StreamResult(stringWriter)); 
      resultXml = stringWriter.toString(); 
     } catch (TransformerException e) { 
      System.out.flush(); 
      final String systemOut = systemOutByteArrayOutputStream.toString(); 
      System.err.flush(); 
      final String systemErr = systemErrByteArrayOutputStream.toString(); 

      throw new ConvertWithXslException("TransformerException - " + e.getMessageAndLocation() 
          + (systemOut.length() > 0 ? ("\nSystem.out:" + systemOut) : "") 
          + (systemErr.length() > 0 ? ("\nSystem.err:" + systemErr) : ""), e); 
     } finally { 
      System.setOut(oldSystemOutPrintStream); 
      System.setErr(oldSystemErrPrintStream); 
     } 

     return resultXml; 
    } 
} 
+0

Какой выход он не поймает? Все, что он хочет, это ошибка. Для этого это слишком много. Плюс, что, если его сервер выводит что-то еще, пока это работает, потому что это многопоточная система? Пользователь увидит этот вывод в сообщении, которое они получают с ошибкой. Это нехорошее решение. – Brian

+0

зависит от двигателя трансформатора. Некоторый (полезный) выход идет в System.out. unfortunaly ErrorListener не поймать это. –

+0

, чтобы избежать улова другой резьбы, используйте решение maiaco. замечательно. –

0

Во-первых, это, вероятно, что любое решение будет зависеть от вашего выбора процессора XSLT. Различные реализации интерфейса JAXP могут обеспечить различную информацию в тех исключениях, которые они генерируют.

Возможно, ошибка в синтаксическом анализе XML доступна в обернутом исключении. По историческим причинам TransformerConfigurationException предлагает getException() и getCause() для доступа к завернутым исключениям, и, возможно, стоит проверить их обоих.

В качестве альтернативы, возможно, что информация была предоставлена ​​в отдельном вызове ErrorListener.

И, наконец, эта конкретная ошибка обнаруживается парсером XML (а не XSLT-процессором), поэтому в первом случае он будет обрабатываться синтаксическим анализатором. Возможно, стоит установить параметр ErrorHandler парсера и ловить ошибки анализа на этом уровне. Если вам нужен явный контроль над парсером XML, используемым преобразованием, используйте SAXSource, XMLReader которого соответствующим образом инициализируется.

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