package org.mindswap.swoop.utils;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
// $Id: hyperdaml.java,v 1.22 2002/08/14 21:49:14 mdean Exp $
/**
* produce a hypertext version of a DAML/RDF document.
*/
public class HyperDAML
{
static PrintWriter out = null;
static String source = null;
static String prefix = "";
/**
* are we being run as a non-parsed-header CGI script?
*/
static boolean nph = false;
static int rdfDepth = 0; // just in case rdf:RDF is erroneously nested
static String quoted(String string)
{
return '"' + string + '"';
}
/**
* escape HTML characters
*/
static String escaped(String string)
{
StringBuffer retval = new StringBuffer();
for (int i = 0; i < string.length(); i++)
{
char ch = string.charAt(i);
switch (ch)
{
case '<':
retval.append("<");
break;
case '>':
retval.append(">");
break;
case '&':
retval.append("&");
break;
default:
retval.append(ch);
}
}
return retval.toString();
}
/**
* determine if this is the RDF (M&S) namespace
*/
static boolean rdfNamespace(String namespaceURI)
{
return namespaceURI.equals("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
}
/**
* determine if this is the named RDF attribute.
*/
static boolean rdfAttribute(org.xml.sax.Attributes atts, int index, String name)
{
String localName = atts.getLocalName(index);
// be liberal about namespaces
return localName.equals(name);
}
static String maybeApplyPrefix(String uri)
{
// check if self-relative
if (uri.equals("")
|| (uri.charAt(0) == '#'))
return uri;
else
return prefix + uri;
}
/**
* turn a relative URI into an absolute URI
*/
static String makeAbsolute(String maybeRelative)
{
try {
return new java.net.URL(new java.net.URL(source),
maybeRelative).toString();
} catch (java.net.MalformedURLException e) {
return maybeRelative;
}
}
static public String formatRDF(String rdf, String source) throws ParserConfigurationException, IOException, SAXException {
HyperDAML.source = source;
StringWriter sw = new StringWriter();
out = new PrintWriter(sw);
generate(rdf);
return sw.getBuffer().toString();
}
static void generate(String rdf) throws ParserConfigurationException, IOException, SAXException
{
javax.xml.parsers.SAXParserFactory spf = javax.xml.parsers.SAXParserFactory.newInstance();
spf.setValidating(false); // not needed for our use -- reinforce default
javax.xml.parsers.SAXParser saxParser = spf.newSAXParser();
org.xml.sax.XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.setFeature("http://xml.org/sax/features/namespaces", true);
// get xmlns attributes
xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
org.xml.sax.helpers.DefaultHandler handler = new org.xml.sax.helpers.DefaultHandler()
{
boolean foundDAML = false;
boolean startedHTML = false;
org.xml.sax.Locator locator;
/**
* stack indicating whether each level of element has children.
*/
java.util.Stack elementStack = new java.util.Stack();
/**
* code to check if this is the first child for the parent element
*/
void child()
{
if (elementStack.empty())
return;
Boolean b = (Boolean) elementStack.peek();
if (b.equals(Boolean.TRUE))
{
// not first child
return;
}
// close element start
out.print(">");
elementStack.pop();
elementStack.push(Boolean.TRUE);
}
public void setLocator(org.xml.sax.Locator l)
{
locator = l;
}
public void startDocument()
{
}
void startHTML()
{
if (startedHTML)
return;
out.println("<html>");
out.println(" <body>");
startedHTML = true;
}
public void startElement(String namespaceURI, String localName,
String rawName, org.xml.sax.Attributes atts)
throws org.xml.sax.SAXException
{
if (rdfNamespace(namespaceURI)
&& localName.equals("RDF"))
{
rdfDepth++;
if (! foundDAML)
{
// first time
if (nph)
{
out.println("HTTP/1.1 200 OK");
out.println("Content-type: text/html");
out.println();
}
startHTML();
out.println(" <code>");
out.println(" <pre>");
out.println("<font face=\"Verdana\" size=2>");
}
foundDAML = true;
}
if (rdfDepth == 0)
return;
child(); // of any parent
elementStack.push(Boolean.FALSE);
out.print("<<a href=" + quoted(maybeApplyPrefix(makeAbsolute(namespaceURI + localName))) + ">" + rawName + "</a>");
// attributes
for (int i = 0; i < atts.getLength(); i++)
{
String attrLocalName = atts.getLocalName(i);
String attrQName = atts.getQName(i);
String value = atts.getValue(i);
boolean hyperlink = (rdfAttribute(atts, i, "resource")
|| rdfAttribute(atts, i, "about"));
boolean namespace = (attrQName.equals("xmlns")
|| attrQName.startsWith("xmlns:"));
if (rdfAttribute(atts, i, "ID"))
out.print("<a name=" + quoted(value) + " />");
if (namespace) {
out.print(" " + atts.getQName(i) + "=");
out.println(quoted("<a href=" + quoted(maybeApplyPrefix(value)) + ">" + value + "</a>"));
}
else{
out.print(" " + atts.getQName(i) + "=");
if (hyperlink)
out.print(quoted("<a href=" + quoted(maybeApplyPrefix(value)) + ">" + value + "</a>"));
else
out.print(quoted(value));
}
}
}
public void characters(char [] ch, int start, int length)
{
if (rdfDepth == 0)
return;
child();
for (int i = 0; i < length; i++)
out.print(ch[start + i]);
}
public void ignorableWhitespace(char [] ch, int start, int length)
{
// handle like text
characters(ch, start, length);
}
public void endElement(String uri, String localName, String qName)
{
if (rdfDepth == 0)
return;
Boolean b = (Boolean) elementStack.pop();
if (b.equals(Boolean.FALSE))
out.print("/>");
else
out.print("</<a href=" + quoted(maybeApplyPrefix(makeAbsolute(uri + localName))) + ">" + qName + "</a>>");
if (rdfNamespace(uri)
&& localName.equals("RDF"))
{
rdfDepth--;
//out.println("<br />");
//BJP: The problem is that the HTML renderer can't handle
// this classic XHTML/HTML trick. So, suppress the trick.
out.println("<br>");
}
}
/**
* redirect to the original document if it doesn't seem to contain DAML
*/
void maybeRedirect()
{
if (nph && (! foundDAML))
{
out.println("HTTP/1.1 301 Redirect");
out.println("Location: " + source);
out.println();
System.exit(0);
}
}
public void endDocument()
{
maybeRedirect();
startHTML();
if (foundDAML)
{
out.println();
out.println(" </font>");
out.println(" </pre>");
out.println(" </code>");
}
else
{
out.println(" No DAML or RDF content found.");
}
// out.println(" <hr />");
// out.println(" <address>");
// out.println(" Produced from");
// out.println(" <a href=" + quoted(source) + ">" + source + "</a>");
// out.println(" using");
// out.println(" <a href=" + quoted("http://www.daml.org/2001/04/hyperdaml/") + ">hyperdaml</a>.java");
// out.println(" </address>");
out.println(" </font>");
out.println(" </body>");
out.println("</html>");
}
void printException(String label,
org.xml.sax.SAXParseException e)
{
maybeRedirect();
startHTML();
System.err.println(label + ": " + escaped(e.toString()));
}
public void warning(org.xml.sax.SAXParseException e)
{
printException("warning", e);
}
public void error(org.xml.sax.SAXParseException e)
{
printException("recoverable error", e);
}
public void fatalError(org.xml.sax.SAXParseException e)
{
printException("fatal error", e);
endDocument();
}
};
xmlReader.setContentHandler(handler);
xmlReader.setErrorHandler(handler);
xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler",
new org.xml.sax.ext.LexicalHandler()
{
public void comment(char [] ch, int start, int length)
{
if (rdfDepth == 0)
return;
out.print("<!--");
for (int i = 0; i < length; i++)
out.print(ch[start + i]);
out.print("-->");
}
public void endCDATA()
{
}
public void endDTD()
{
}
public void endEntity(String name)
{
}
public void startCDATA()
{
}
public void startDTD(String name, String publicId, String systemId)
{
}
public void startEntity(String name)
{
}
});
xmlReader.parse(new InputSource(new StringReader(rdf)));
}
}