org.rascalmpl.library.lang.xml.DOM.java Source code

Java tutorial

Introduction

Here is the source code for org.rascalmpl.library.lang.xml.DOM.java

Source

/*******************************************************************************
 * Copyright (c) 2009-2013 CWI
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
    
 *   * Tijs van der Storm - Tijs.van.der.Storm@cwi.nl
 *   * Mark Hills - Mark.Hills@cwi.nl (CWI)
*******************************************************************************/
package org.rascalmpl.library.lang.xml;

import java.io.CharArrayReader;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;

import org.jdom2.Attribute;
import org.jdom2.CDATA;
import org.jdom2.Comment;
import org.jdom2.Content;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.EntityRef;
import org.jdom2.JDOMException;
import org.jdom2.Namespace;
import org.jdom2.ProcessingInstruction;
import org.jdom2.Text;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.rascalmpl.value.IConstructor;
import org.rascalmpl.value.IInteger;
import org.rascalmpl.value.IList;
import org.rascalmpl.value.IListWriter;
import org.rascalmpl.value.IString;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.IValueFactory;

public class DOM {
    private final IValueFactory vf;

    public DOM(IValueFactory vf) {
        this.vf = vf;
    }

    private static class Skip extends Exception {
        private static final long serialVersionUID = -6330585199877497106L;
    }

    public IConstructor parseXMLDOMTrim(IString str) throws IOException, JDOMException {
        return parseXMLDOM(str, true);
    }

    public IConstructor parseXMLDOM(IString str) throws IOException, JDOMException {
        return parseXMLDOM(str, false);
    }

    public IString xmlRaw(IConstructor node) throws IOException {
        return xmlToString(node, Format.getRawFormat());
    }

    public IString xmlPretty(IConstructor node) throws IOException {
        return xmlToString(node, Format.getPrettyFormat());
    }

    public IString xmlCompact(IConstructor node) throws IOException {
        return xmlToString(node, Format.getCompactFormat());
    }

    private IConstructor parseXMLDOM(IString str, boolean trim) throws JDOMException, IOException {
        SAXBuilder builder = new SAXBuilder();
        CharArrayReader reader = new CharArrayReader(str.getValue().toCharArray());
        Document doc = builder.build(reader);
        return convertDocument(doc, trim);
    }

    private IString xmlToString(IConstructor node, Format format) throws IOException {
        StringWriter writer = new StringWriter();
        writeXML(writer, nodeToDocument(node), format);
        return vf.string(writer.toString());
    }

    private void writeXML(Writer writer, Document document, Format format) throws IOException {
        XMLOutputter outputter = new XMLOutputter(format);
        outputter.output(document, writer);
        writer.close();
    }

    private Document nodeToDocument(IConstructor node) {
        if (node.getType() != Factory.Node) {
            wellformednessError();
        }
        if (node.getConstructorType() != Factory.Node_document
                && node.getConstructorType() != Factory.Node_element) {
            wellformednessError();
        }

        if (node.getConstructorType() == Factory.Node_document) {
            return new Document(nodeToElement((IConstructor) node.get(0)));
        }
        return new Document(nodeToElement(node));
    }

    private Element nodeToElement(IConstructor elt) {
        IConstructor ns = (IConstructor) elt.get(0);
        IString name = (IString) elt.get(1);
        IList kids = (IList) elt.get(2);
        Element e = new Element(name.getValue(), namespaceToNamespace(ns));
        for (IValue k : kids) {
            IConstructor n = (IConstructor) k;
            if (n.getConstructorType() == Factory.Node_attribute) {
                e.setAttribute(nodeToAttribute(n));
            } else {
                e.addContent(nodeToContent(n));
            }
        }
        return e;
    }

    private Content nodeToContent(IConstructor n) {
        if (n.getConstructorType() == Factory.Node_element) {
            return nodeToElement(n);
        }
        if (n.getConstructorType() == Factory.Node_pi) {
            IString target = (IString) n.get(0);
            IString data = (IString) n.get(1);
            return new ProcessingInstruction(target.getValue(), data.getValue());

        }
        if (n.getConstructorType() == Factory.Node_charRef) {
            IInteger code = (IInteger) n.get(0);
            int c = java.lang.Integer.parseInt(code.getStringRepresentation());
            return new Text(new java.lang.String(Character.toChars(c)));
        }
        if (n.getConstructorType() == Factory.Node_entityRef) {
            return new EntityRef(((IString) n.get(0)).getValue());
        }

        java.lang.String text = ((IString) n.get(0)).getValue();
        if (n.getConstructorType() == Factory.Node_cdata) {
            return new CDATA(text);
        }
        if (n.getConstructorType() == Factory.Node_charData) {
            return new Text(text);
        }
        if (n.getConstructorType() == Factory.Node_comment) {
            return new Comment(text);
        }

        wellformednessError();
        return null;
    }

    private Attribute nodeToAttribute(IConstructor n) {
        IConstructor ns = (IConstructor) n.get(0);
        IString name = (IString) n.get(1);
        IString data = (IString) n.get(2);
        return new Attribute(name.getValue(), data.getValue(), namespaceToNamespace(ns));
    }

    private Namespace namespaceToNamespace(IConstructor ns) {
        if (ns.getConstructorType() == Factory.Namespace_none) {
            return Namespace.NO_NAMESPACE;
        }
        IString prefix = (IString) ns.get(0);
        IString uri = (IString) ns.get(1);
        return Namespace.getNamespace(prefix.getValue(), uri.getValue());
    }

    private void wellformednessError() {
        throw new RuntimeException("Nonwellformed XML node (TODO: make Rascal runtime exception)");
    }

    private IConstructor convertDocument(Document doc, boolean trim) {
        IConstructor root = convertElement(doc.getRootElement(), trim);
        return vf.constructor(Factory.Node_document, root);
    }

    private IConstructor convertElement(Element e, boolean trim) {
        IListWriter kids = vf.listWriter(Factory.Node);
        for (Object o : e.getAttributes()) {
            Attribute attr = (Attribute) o;
            IString key = vf.string(attr.getName());
            IString val = vf.string(attr.getValue());

            kids.insert(vf.constructor(Factory.Node_attribute, convertNamespace(attr.getNamespace()), key, val));
        }

        int len = e.getContentSize();
        for (int i = 0; i < len; i++) {
            try {
                kids.append(convertContent(e.getContent(i), trim));
            } catch (Skip c) { // Ugh, terrible, but I'm in hurry
                continue;
            }
        }

        IString name = vf.string(e.getName());
        return vf.constructor(Factory.Node_element, convertNamespace(e.getNamespace()), name, kids.done());
    }

    private IConstructor convertNamespace(Namespace ns) {
        if (ns == Namespace.NO_NAMESPACE) {
            return vf.constructor(Factory.Namespace_none);
        }
        IString prefix = vf.string(ns.getPrefix());
        IString uri = vf.string(ns.getURI());
        IConstructor nscon = vf.constructor(Factory.Namespace_namespace, prefix, uri);
        return nscon;
    }

    private IConstructor convertContent(Content content, boolean trim) throws Skip {
        if (content instanceof Element) {
            return convertElement((Element) content, trim);
        }
        if (content instanceof CDATA) { // CDATA first (is subtype of Text)
            CDATA cdata = (CDATA) content;
            return vf.constructor(Factory.Node_cdata, getString(trim, cdata));
        }
        if (content instanceof Text) {
            Text text = (Text) content;
            return vf.constructor(Factory.Node_charData, getString(trim, text));
        }
        if (content instanceof Comment) {
            Comment comment = (Comment) content;
            IString data = vf.string(comment.getText());
            return vf.constructor(Factory.Node_comment, data);
        }
        if (content instanceof ProcessingInstruction) {
            ProcessingInstruction pi = (ProcessingInstruction) content;
            IString data = vf.string(pi.getData());
            return vf.constructor(Factory.Node_pi, data);
        }
        if (content instanceof EntityRef) {
            EntityRef er = (EntityRef) content;
            IString data = vf.string(er.getName());
            return vf.constructor(Factory.Node_entityRef, data);
        }
        throw new AssertionError("cannot convert JDOM content type " + content.getClass());
    }

    private IString getString(boolean trim, Text text) throws Skip {
        if (trim) {
            java.lang.String s = text.getTextTrim();
            if ("".equals(s)) {
                throw new Skip();
            }
            return vf.string(s);
        }
        return vf.string(text.getText());
    }
}