import org.apache.xalan.xslt.XSLTProcessor;
import org.apache.xalan.xslt.XSLTInputSource;
import org.apache.xalan.xslt.XSLTResultTarget;
import org.apache.xalan.xslt.XSLTProcessorFactory;
import org.apache.xalan.xslt.StylesheetRoot;
import org.xml.sax.*;
import java.io.*;
/** Translate XML to LaTeX, using a suitable XSL transformation first.
* By default an element 'data' is translated to '\xxx{data}'.
* However, '.' in a tag-name becomes '*' in the output. Thus
* 'Abstract' becomes '\subsection*{Abstract}'.
* Some element names are handled specially:
* 'data' is output as '{data}'.
* '' is output as '\arg{}'.
* '' is output as 'arg' with no escapes.
* 'data' causes 'data' to be output verbatim using '\verb'.
* ' becomes '\setlength{\dim}{val}'.
* 'text creates a double-'\n'-delimited paragraph.
* '' becomes '\begin{foo}[X]{Y}'.
* '' becomes '\end{foo}'.
* Text data is translated to use corresponding LaTeX escape sequences.
*/
public class TransformToLatex implements org.xml.sax.DocumentHandler
{
PrintWriter out;
char verbDelimiter = ' ';
char prevChar = '\0';
boolean strippingSpaces = false;
public TransformToLatex(PrintWriter out)
{
this.out = out;
}
public void setDocumentLocator (Locator locator)
{
}
public void startDocument ()
throws SAXException
{
}
public void endDocument ()
throws SAXException
{
out.close();
}
public void startElement (String name, AttributeList atts)
throws SAXException
{
String arg;
strippingSpaces = false;
if ("brace.".equals(name))
{
prevChar = '{';
out.print('{');
}
else if ("cmd.".equals(name))
{
out.print("\\");
arg = atts.getValue("name");
if (arg == null)
{
System.err.println("missing name attribute in cmd.");
arg = "?unknown?";
}
out.print(arg);
out.print(' ');
prevChar = ' ';
strippingSpaces = true;
}
else if ("tex.".equals(name))
{
arg = atts.getValue("value");
if (arg == null)
{
System.err.println("missing value attribute in tex.");
arg = "?unknown?";
}
out.print(arg);
prevChar = arg.charAt(arg.length()-1);
}
else if ("setlength.".equals(name))
{
out.print("\n\\setlength{\\");
arg = atts.getValue("name");
if (arg == null)
{
System.err.println("missing name attribute in cmd.");
arg = "?unknown?";
}
out.print(arg);
out.print("}{");
arg = atts.getValue("value");
if (arg == null)
{
System.err.println("missing value attribute in cmd.");
arg = "?unknown?";
}
out.print(arg);
out.print("}\n");
prevChar = '\n';
}
else if ("verb.".equals(name))
{
verbDelimiter = '|';
out.print("\\verb");
out.print(verbDelimiter);
prevChar = verbDelimiter;
}
else if ("par.".equals(name))
{
if (prevChar != '\n')
out.print('\n');
out.print('\n');
prevChar = '\n';
}
else if (name.startsWith("begin-"))
{
if (prevChar != '\n')
out.print('\n');
out.print('\\');
out.print("begin");
out.print('{');
out.print(name.substring(6));
out.print('}');
arg = atts.getValue("opt-arg1");
if (arg != null)
{
out.print('[');
out.print(arg);
out.print(']');
}
arg = atts.getValue("opt-arg2");
if (arg != null)
{
out.print('[');
out.print(arg);
out.print(']');
}
arg = atts.getValue("req-arg1");
if (arg != null)
{
out.print('{');
out.print(arg);
out.print('}');
}
arg = atts.getValue("req-arg2");
if (arg != null)
{
out.print('{');
out.print(arg);
out.print('}');
}
prevChar = '}';
}
else if (name.startsWith("end-"))
{
if (prevChar != '\n')
out.print('\n');
out.print('\\');
out.print("end");
out.print('{');
out.print(name.substring(4));
out.print('}');
prevChar = '}';
}
else
{
if (name.equals("begin") || name.equals("end"))
out.print('\n');
out.print('\\');
name = name.replace('.', '*');
out.print(name);
arg = atts.getValue("opt-arg1");
if (arg != null)
{
out.print('[');
out.print(arg);
out.print(']');
}
arg = atts.getValue("opt-arg2");
if (arg != null)
{
out.print('[');
out.print(arg);
out.print(']');
}
out.print("{");
prevChar = '{';
}
}
public void endElement (String name)
throws SAXException
{
if ("brace.".equals(name))
{
out.print('}');
}
else if ("par.".equals(name))
{
if (prevChar != '\n')
out.print('\n');
out.print('\n');
prevChar = '\n';
}
else if ("verb.".equals(name))
{
out.print(verbDelimiter);
prevChar = verbDelimiter;
verbDelimiter = ' ';
}
else if (name.startsWith("begin-") || name.startsWith("end-"))
{
out.print('\n');
prevChar = '\n';
}
else if (! ("cmd.".equals(name)) && ! ("setlength.".equals(name))
&& ! ("tex.".equals(name)))
{
out.print('}');
if (name.equals("begin") || name.equals("end"))
{
out.print('\n');
prevChar = '\n';
}
else
prevChar = '{';
}
strippingSpaces = true;
}
public void characters (char ch[], int start, int length)
throws SAXException
{
for (int i = 0; i < length; i++)
{
char c = ch[i];
if (i == 0)
{
if (c == ' ' && strippingSpaces)
out.print("{}");
strippingSpaces = false;
}
if (verbDelimiter != ' ')
{
if (c == verbDelimiter)
{
out.print(verbDelimiter);
out.print("\\verb");
verbDelimiter = verbDelimiter == '|' ? '%' : '|';
out.print(verbDelimiter);
}
out.print(c);
prevChar = c;
}
else
{
switch(c)
{
case '\u00c5': out.print("\\AA{}"); break; // A-ring
case '\u00c4': out.print("\\\"A{}"); break; // A-diaeresis
case '\u00c6': out.print("\\AE{}"); break; // AE
case '\u00e4': out.print("\\\"a{}"); break; // a-diaeresis
case '\u00e5': out.print("\\aa{}"); break; // a-ring
case '\u00e6': out.print("\\ae{}"); break; // ae
case '\u00d6': out.print("\\\"O{}"); break; // O-diaeresis
case '\u00d8': out.print("\\O{}"); break; // O-stroke
case '\u00f6': out.print("\\\"o{}"); break; // o-diaeresis
case '\u00f8': out.print("\\o{}"); break; // o-stroke
case '_': out.print("{\\_}"); break;
case '\\': out.print("\\verb|\\|"); break;
case '{': out.print("\\verb|{|"); break;
case '}': out.print("\\verb|}|"); break;
default:
out.print(c);
}
prevChar = c; // A harmless gray lie.
}
}
}
public void ignorableWhitespace (char ch[], int start, int length)
throws SAXException
{
}
public void processingInstruction (String target, String data)
throws SAXException
{
}
public static void main(String[] args)
throws java.io.IOException,
java.net.MalformedURLException,
org.xml.sax.SAXException
{
XSLTProcessor processor = XSLTProcessorFactory.getProcessor();
// Set the processor to use a compiled stylesheet.
// The stylesheet provides access to a SAX DocumentHandler,
// passing it the stylesheet xsl:output settings.
StylesheetRoot stylesheet = processor.processStylesheet(args[1]);
// This property was just set implicitly, but for good form...
processor.setStylesheet(stylesheet);
// In this case, send the output to System.out.
PrintWriter out = new PrintWriter(new FileWriter(args[2]));
org.xml.sax.DocumentHandler dh = new TransformToLatex(out);
// Use the DocumentHandler to construct an XSLTResultTarget object.
XSLTResultTarget saxResult = new XSLTResultTarget(dh);
// Perform the transformation. The stylesheet parameter is null, so
// the processor uses the compiled stylesheet identified by its
// Stylesheet property setting.
processor.process(new XSLTInputSource(args[0]), null, saxResult);
}
}