package com.thaiopensource.validate.schematron;

import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXParseException;
import org.xml.sax.SAXException;
import org.xml.sax.Attributes;

class OutputHandler extends DefaultHandler {
  private final ErrorHandler eh;
  private int lineNumber = -1;
  private String systemId = null;
  private StringBuffer message = new StringBuffer();
  private boolean inMessage = false;

  OutputHandler(ErrorHandler eh) {
    this.eh = eh;
  }

  public void characters(char ch[], int start, int length)
          throws SAXException {
    if (inMessage)
      message.append(ch, start, length);
  }

  public void ignorableWhitespace(char ch[], int start, int length)
          throws SAXException {
    characters(ch, start, length);
  }

  public void startElement(String uri, String localName,
                           String qName, Attributes attributes)
          throws SAXException {
    if (localName.equals("failed-assertion")
        || localName.equals("report")) {
      String value = attributes.getValue("", "line-number");
      if (value == null)
        lineNumber = -1;
      else {
        try {
          lineNumber = Integer.parseInt(value);
        }
        catch (NumberFormatException e) {
          lineNumber = -1;
        }
      }
      value = attributes.getValue("", "system-id");
      if (value != null && value.equals(""))
        value = null;
      systemId = value;
    }
    else if (localName.equals("statement"))
      inMessage = true;
    else if (localName.equals("diagnostic")) {
      inMessage = true;
      message.append("\n  ");
    }
  }

  public void endElement(String uri, String localName, String qName)
          throws SAXException {
    if (localName.equals("statement") || localName.equals("diagnostic"))
      inMessage = false;
    else if (localName.equals("failed-assertion")
             || localName.equals("report")) {
      eh.error(new SAXParseException(message.toString(), null, systemId, lineNumber, -1));
      message.setLength(0);
    }
  }
}

@@ -453,16 +453,54 @@
 = false;
+%0A  private final String lineSeparator;
 %0A%0A  Outp
@@ -546,16 +546,79 @@
 h = eh;%0A
+    this.lineSeparator = System.getProperty(%22line.separator%22);%0A
   %7D%0A%0A  p
@@ -727,49 +727,400 @@
 age)
+ %7B
 %0A      
-message.append(ch, start, length);
+for (int i = 0; i %3C length; i++) %7B%0A        char c = ch%5Bstart + i%5D;%0A        switch (c) %7B%0A        case ' ':%0A        case '%5Cr':%0A        case '%5Cn':%0A        case '%5Ct':%0A          if (message.length() == 0 %7C%7C message.charAt(message.length() - 1) != ' ')%0A            message.append(' ');%0A          break;%0A        default:%0A          message.append(c);%0A          break;%0A        %7D%0A      %7D%0A    %7D
 %0A  %7D
@@ -2069,32 +2069,197 @@
 e = true;%0A      
+if (message.length() %3E 0 && message.charAt(message.length() - 1) == ' ')%0A        message.setLength(message.length() - 1);%0A      message.append(lineSeparator);%0A      
 message.append(%22
@@ -2258,18 +2258,16 @@
 append(%22
-%5Cn
   %22);%0A  
@@ -2516,32 +2516,32 @@
 led-assertion%22)%0A
-
              %7C%7C 
@@ -2566,24 +2566,152 @@
 report%22)) %7B%0A
+      if (message.length() %3E 0 && message.charAt(message.length() - 1) == ' ')%0A        message.setLength(message.length() - 1);%0A
       eh.err

Normalize space