[Nodal-cvs] nodal/j-src/org/nodal/format/application/xml Format.java,NONE,1.1 XMLFactory.java,NONE,1
Status: Pre-Alpha
Brought to you by:
leei
From: Lee I. <le...@us...> - 2004-11-18 23:30:49
|
Update of /cvsroot/nodal/nodal/j-src/org/nodal/format/application/xml In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15230/org/nodal/format/application/xml Added Files: Format.java XMLFactory.java Log Message: Make application/xml the default MIME type for XML --- NEW FILE: XMLFactory.java --- /* * Distributed under the Apache Software License, Version 1.1 (see below, or * the file LICENSE for terms and conditions) * * Copyright (c) 2004 University of British Columbia. All rights reserved. * * Created on Mar 10, 2004 by leei */ package org.nodal.format.application.xml; import org.nodal.Types; import org.nodal.model.NodeFactory; import org.nodal.model.MapNode; import org.nodal.model.RecordNode; import org.nodal.model.SequenceNode; import org.nodal.type.MapType; import org.nodal.type.NodeType; import org.nodal.type.RecordType; import org.nodal.type.Schema; import org.nodal.type.SequenceType; import org.nodal.util.ConstraintFailure; import org.nodal.util.IndexBoundsException; import org.nodal.util.Name; import org.nodal.util.Names; /** * @author leei */ public class XMLFactory { /** * The xml.nls schema, a collection of all of the basic XML types. */ public static final Schema schema = Types .openBaseSchema("xml.nls"); public static final RecordType notationType = (RecordType) schema .typeNamed("Notation"); public static final RecordType documentType = (RecordType) schema .typeNamed("Document"); public static final RecordType docTypeType = (RecordType) schema .typeNamed("DocumentType"); public static final RecordType elementType = (RecordType) schema .typeNamed("Element"); public static final RecordType commentType = (RecordType) schema .typeNamed("Comment"); public static final RecordType textType = (RecordType) schema .typeNamed("Text"); public static final RecordType piType = (RecordType) schema .typeNamed("ProcessingInstruction"); public static final SequenceType nodeListType = (SequenceType) schema .typeNamed("NodeList"); public static final MapType attrMapType = (MapType) elementType .fieldType("attributes"); public static final RecordType chardataType = (RecordType) schema .typeNamed("CharacterData"); public static final RecordType cdataType = (RecordType) schema .typeNamed("CDATASection"); private NodeFactory factory; /** * */ public XMLFactory(NodeFactory factory) { this.factory = factory; } public RecordNode.Editor createDocument() { return factory.createNode(documentType).editRecord(); } public RecordNode.Editor createDocumentType() { return factory.createNode(docTypeType).editRecord(); } public RecordNode.Editor createElement() { return factory.createNode(elementType).editRecord(); } public RecordNode.Editor createElement(Name tagName) throws ConstraintFailure { RecordNode.Editor element = createElement(); element.setField("tagName").set(tagName); return element; } public MapNode.Editor createNamespaceMap(RecordNode.Editor element) throws ConstraintFailure { NodeType nsType = (NodeType) elementType.fieldType("namespaces"); MapNode.Editor map = factory.createNode(nsType).editMap(); element.setField("namespaces").setNode(map); return map; } public RecordNode.Editor createText() { return factory.createNode(textType).editRecord(); } public RecordNode.Editor setCData(RecordNode.Editor editor, String data) throws ConstraintFailure { editor.setField("data").setNode(createString(data)); return editor; } public RecordNode.Editor createText(String data) throws ConstraintFailure { RecordNode.Editor text = createText(); return setCData(text, data); } public RecordNode.Editor createComment() { return factory.createNode(commentType).editRecord(); } public RecordNode.Editor createComment(String data) throws ConstraintFailure { RecordNode.Editor comment = createComment(); return setCData(comment, data); } public RecordNode.Editor createProcessingInstruction() { return factory.createNode(piType).editRecord(); } public RecordNode.Editor createProcessingInstruction(String target, String data) throws ConstraintFailure { RecordNode.Editor pi = createProcessingInstruction(); pi.setField("target").set(Names.getName(target)); return setCData(pi, data); } public RecordNode.Editor createCData() { return factory.createNode(cdataType).editRecord(); } public RecordNode.Editor createCData(String data) throws ConstraintFailure { RecordNode.Editor comment = createCData(); return setCData(comment, data); } public MapNode.Editor createAttributeMap() { return factory.createNode(attrMapType).editMap(); } public SequenceNode.Editor createNodeList() { return factory.createNode(nodeListType).editSequence(); } public SequenceNode.Editor createNodeList(NodeType t) { return factory.createNode(t).editSequence(); } public SequenceNode.Editor createString(String s) { SequenceNode.Editor editor = factory.createNode(Types.STRING) .editSequence(); try { editor.replaceRange(0, -1).setString(s); } catch (IndexBoundsException e) { return null; } catch (ConstraintFailure e) { return null; } return editor; } } --- NEW FILE: Format.java --- /* * Created on Nov 6, 2003 * * To change the template for this generated file go to * Window>Preferences>Java>Code Generation>Code and Comments */ package org.nodal.format.application.xml; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.jdom.Attribute; import org.jdom.CDATA; import org.jdom.Comment; import org.jdom.DocType; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.ProcessingInstruction; import org.jdom.Text; import org.jdom.input.SAXBuilder; import org.nodal.filesystem.DocumentFormat; import org.nodal.model.MapNode; import org.nodal.model.Node; import org.nodal.model.NodeFactory; import org.nodal.model.RecordNode; import org.nodal.model.SequenceNode; import org.nodal.model.Setter; import org.nodal.type.NodeType; import org.nodal.util.ConstraintFailure; import org.nodal.util.IndexBoundsException; import org.nodal.util.Name; import org.nodal.util.Names; import org.nodal.util.Namespace; import org.xml.sax.InputSource; /** * Implementation of the text/xml DocumentFormat handler. Decodes and encodes * XML data using the base schema xml.nls. * * Built using the org.jdom parser interface. * * @author leei */ public class Format extends DocumentFormat.AutoRegister { /** * Singleton instance of Format class. */ private static final Format format = new Format(); public DocumentFormat create () { return format; } /** * Ensure that above singleton instance is only one created. * */ private Format () { } /* * (non-Javadoc) * * @see org.nodal.filesystem.DocumentFormat#mimeType() */ public String mimeType() { return "application/xml"; } /* * (non-Javadoc) * * @see org.nodal.filesystem.DocumentFormat#rootType() */ public NodeType rootType() { return XMLFactory.documentType; } private static class NSChain { MapNode nsMap; NSChain chain; NSChain(MapNode nsMap, NSChain chain) { this.nsMap = nsMap; this.chain = chain; } String qName(Name nm) { Namespace ns = nm.namespace(); // Check for global Namespace if (ns.uri() == null) { return nm.string(); } Name uri = Names.getName(ns.uri()); NSChain cv = this; Name prefix; do { prefix = (Name) cv.nsMap.getValue(uri); cv = cv.chain; } while (cv != null && prefix == null); if (prefix == null) { return nm.string(); } else { return prefix.string() + ":" + nm.string(); } } } /* * (non-Javadoc) * * @see org.nodal.filesystem.DocumentFormat#encoder() */ public DocumentFormat.Encoder encoder() { return new Encoder(); } private class Encoder implements DocumentFormat.Encoder { /* * (non-Javadoc) * * @see org.nodal.filesystem.DocumentFormat.Encoder#isLossless() */ public boolean isLossless() { return false; } /* * (non-Javadoc) * * @see org.nodal.filesystem.DocumentFormat.Encoder#encode(java.io.OutputStream, * org.nodal.model.Node) */ public OutputStream encode(OutputStream stream, Node root) throws IOException { PrintWriter pr = new PrintWriter(stream); encodeDocument(pr, root.asRecordNode()); pr.println(); pr.flush(); return stream; } private void encodeDocument(PrintWriter out, RecordNode docNode) throws IOException { out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); Node typeNode = docNode.field("docType").getNode(); if (typeNode != null) { RecordNode docType = typeNode.asRecordNode(); Name name = (Name) docType.getField("name"); Name pubID = (Name) docType.getField("publicID"); Name sysID = (Name) docType.getField("systemID"); Name internalSubset = (Name) docType.getField("internalSubset"); out.print("<!DOCTYPE " + name.string()); if (pubID != null) { out.print(" PUBLIC \"" + pubID.string() + "\""); if (sysID != null) { out.print(" \"" + sysID.string() + "\""); } } else if (sysID != null) { out.print(" SYSTEM \"" + sysID.string() + "\""); } if (internalSubset != null && internalSubset.string().length() != 0) { out.print("\n["); out.print(internalSubset.string()); out.print("]"); } out.println(">"); } Node chNode = docNode.field("children").getNode(); if (chNode != null) { SequenceNode children = chNode.asSequenceNode(); int n = children.size(); for (int i = 0; i < n; ++i) { Node child = children.item(i).getNode(); encodeNode(out, child, 0, null); } } } private void encodeNode(PrintWriter out, Node node, int indent, NSChain nsChain) { NodeType nodeType = node.nodeType(); if (XMLFactory.chardataType.acceptsType(nodeType)) { RecordNode text = node.asRecordNode(); if (text != null) { encodeText(out, text); } } else if (XMLFactory.elementType.acceptsType(nodeType)) { RecordNode element = node.asRecordNode(); if (element != null) { encodeElement(out, element, indent, nsChain); } } else { out.println("<!-- Ignore XML: " + nodeType + " -->"); } } /** * Returns an XML-qualified name derived from the URI->prefix mappings in * the NSChain. * * @param name * a Nodal Name for the given tag * @param nsChain * a namespace chain (NSChain) holding URI->prefix mappings * @return an XML QName for the name argument */ private String qName(Name name, NSChain nsChain) { if (nsChain == null) { return name.string(); } else { return nsChain.qName(name); } } /** * Encode an XML Element. Handles Namespace declarations properly... * * @param out * @param element * @param indent * @param nsChain */ private void encodeElement(PrintWriter out, RecordNode element, int indent, NSChain nsChain) { // Extend Namespace mapping if necessary Node nsNode = element.field("namespaces").getNode(); MapNode nsMap = null; if (nsNode != null) { nsMap = nsNode.asMapNode(); nsChain = new NSChain(nsMap, nsChain); } // Write tagName opening Name elementName = (Name) element.getField("tagName"); out.print("<" + qName(elementName, nsChain)); // Write Namespace decls if (nsMap != null) { Iterator e = nsMap.properties(); while (e.hasNext()) { Name uri = (Name) e.next(); Name prefix = (Name) nsMap.getValue(uri); out.print(" xmlns"); if (prefix.string().length() != 0) { out.print(":" + prefix.string()); } out.print("=\"" + uri.string() + "\""); } } // Write attributes Node attrNode = element.field("attributes").getNode(); if (attrNode != null) { MapNode attrs = attrNode.asMapNode(); Iterator e = attrs.properties(); while (e.hasNext()) { Name attrName = (Name) e.next(); Name value = (Name) attrs.getValue(attrName); out.print(" " + qName(attrName, nsChain) + "=\"" + value.string() + "\""); } } // Write children Node childNode = element.field("children").getNode(); if (childNode == null) { out.print("/>"); } else { SequenceNode children = childNode.asSequenceNode(); int n = children.size(); out.print(">"); for (int i = 0; i < n; ++i) { Node child = children.item(i).getNode(); encodeNode(out, child, indent + 2, nsChain); } out.print("</" + elementName.string() + ">"); } } /** * Handle any CharacterData type. * * @param out * @param text */ private void encodeText(PrintWriter out, RecordNode text) { boolean isComment = XMLFactory.commentType.accepts(text); boolean isPI = XMLFactory.piType.accepts(text); boolean isCDATA = XMLFactory.cdataType.accepts(text); String end = null; Node dataNode = text.field("data").getNode(); if (dataNode != null) { String str = dataNode.asSequenceNode().range(0, -1).getString(); if (isComment) { out.print("<!--"); end = "-->"; } else if (isPI) { Name target = (Name) text.getField("target"); out.print("<?" + target.string() + " "); end = "?>"; } else if (isCDATA) { out.print("<![CDATA["); end = "]]>"; } out.print(str); if (end != null) { out.print(end); } } } } /* * (non-Javadoc) * * @see org.nodal.filesystem.DocumentFormat#decoder() */ public DocumentFormat.Decoder decoder() { return new Decoder(); } private class Decoder implements DocumentFormat.Decoder { private List exceptions; private InputSource source; private Decoder() { source = new InputSource(); } /* * (non-Javadoc) * * @see org.nodal.filesystem.DocumentFormat.Decoder#isLossless() */ public boolean isLossless() { return false; } /* * (non-Javadoc) * * @see org.nodal.filesystem.DocumentFormat.Decoder#decode(java.io.InputStream, * org.nodal.model.NodeFactory) */ public Node decode(InputStream stream, NodeFactory factory) throws IOException { SAXBuilder builder = new SAXBuilder(); XMLFactory xmlFactory = new XMLFactory(factory); try { source.setByteStream(stream); org.jdom.Document jdomDoc = builder.build(source); return nodalizeDocument(jdomDoc, xmlFactory); } catch (JDOMException e) { exceptions = new LinkedList(); exceptions.add(e); return null; } } /** * Convert a Document from JDOM to an instantiation wrt. NODAL's xml.nls * schema. * * @param jdomDoc * a Document from JDOM * @param factory * a NodeFactory used to create the Nodes in this Document * @return */ private Node nodalizeDocument(Document jdomDoc, XMLFactory factory) { try { //System.out.println("Create xml Document " + documentType); RecordNode.Editor doc = factory.createDocument(); DocType docType = jdomDoc.getDocType(); doc.setField("docType").setNode(nodalizeDocType(docType, factory)); List docContent = jdomDoc.getContent(); if (!docContent.isEmpty()) { SequenceNode.Editor docChildren = doc.createNode( (NodeType) XMLFactory.documentType.fieldType("children")) .editSequence(); doc.setField("children").setNode(docChildren); Setter appender = docChildren.insertAfter(-1); for (Iterator i = docContent.iterator(); i.hasNext();) { appender.setNode(nodalize(i.next(), factory)); } } doc.commit(); return doc; } catch (ConstraintFailure e) { throw new RuntimeException(e); } } /** * Convert a jdom Object into NODAL. * * @param object * a JDOM object * @param factory * a NodeFactory used to create the Nodes * @return a Node */ private Node nodalize(Object object, XMLFactory factory) { // NEXT Nodalize Entities and Notations from XML try { if (object instanceof Comment) { return nodalizeComment((Comment) object, factory); } else if (object instanceof Element) { return nodalizeElement((Element) object, factory); } else if (object instanceof Text) { return nodalizeText((Text) object, factory); } else if (object instanceof CDATA) { return nodalizeCDATA ((CDATA) object, factory); } else if (object instanceof ProcessingInstruction) { return nodalizePI((ProcessingInstruction) object, factory); } else if (object instanceof DocType) { return nodalizeDocType((DocType) object, factory); } else { System.out.println("nodalize: Didn't handle " + object); } } catch (IndexBoundsException e) { throw new RuntimeException(e); } catch (ConstraintFailure e) { throw new RuntimeException(e); } return null; } /** * @param cdata * @param factory * @return */ private Node nodalizeCDATA(CDATA cdata, XMLFactory factory) throws ConstraintFailure { return factory.createCData(cdata.getText()); } /** * @param type * @param factory * @return */ private Node nodalizeDocType(DocType type, XMLFactory factory) throws ConstraintFailure { RecordNode.Editor dtNode = factory.createDocumentType(); String pubID = type.getPublicID(); String sysID = type.getSystemID(); String subset = type.getInternalSubset(); String elementName = type.getElementName(); dtNode.setField("name").setString(elementName); if (pubID != null) { dtNode.setField("publicID").setString(pubID); } if (sysID != null) { dtNode.setField("systemID").setString(sysID); } if (subset != null) { dtNode.setField("internalSubset").setString(subset); } return dtNode; } /** * @param pi * @param factory * @return */ private Node nodalizePI(ProcessingInstruction pi, XMLFactory factory) throws IndexBoundsException, ConstraintFailure { RecordNode.Editor piNode = factory.createProcessingInstruction(pi.getTarget(), pi.getData()); return piNode; } /** * Create a Node of type textType from a JDOM Text object. * * @param text * @param factory * @return @throws * IndexBoundsException * @throws ConstraintFailure */ private Node nodalizeText(Text text, XMLFactory factory) throws IndexBoundsException, ConstraintFailure { RecordNode.Editor textNode = factory.createText(text.getText()); return textNode; } /** * Create a Node of type commentType from a JDOM Comment object. * * @param comment * @param factory * @return @throws * IndexBoundsException * @throws ConstraintFailure */ private Node nodalizeComment(Comment comment, XMLFactory factory) throws IndexBoundsException, ConstraintFailure { RecordNode.Editor commentNode = factory.createComment(comment.getText()); return commentNode; } /** * Create a Node of type elementType from a JDOM Element object. * * @param elem * @param factory * @return @throws * ConstraintFailure */ private Node nodalizeElement(Element elem, XMLFactory factory) throws ConstraintFailure { Namespace ns = Names.getNamespace(elem.getNamespaceURI()); Name tagName = ns.name(elem.getName()); RecordNode.Editor elementNode = factory.createElement(tagName); // Process namespace declarations List namespaces = elem.getAdditionalNamespaces(); if (namespaces != null && !namespaces.isEmpty()) { MapNode.Editor nsMap = factory.createNamespaceMap (elementNode); Iterator i = namespaces.iterator(); while (i.hasNext()) { org.jdom.Namespace nsDecl = (org.jdom.Namespace) i.next(); nsMap.setValue(nsDecl.getURI()).setString(nsDecl.getPrefix()); } } // Process attributes List attrs = elem.getAttributes(); if (!attrs.isEmpty()) { MapNode.Editor attrMap = factory.createAttributeMap(); Iterator i = attrs.iterator(); while (i.hasNext()) { Attribute attr = (Attribute) i.next(); Namespace attrNS = Names.getNamespace(attr.getNamespaceURI()); Name name = attrNS.name(attr.getName()); attrMap.setValue(name).set(attr.getValue()); } elementNode.setField("attributes").setNode(attrMap); } // Process children List ch = elem.getContent(); if (!ch.isEmpty()) { NodeType t = (NodeType) elementNode.nodeType().valueType("children"); SequenceNode.Editor childrenList = factory.createNodeList(t); elementNode.setField("children").setNode(childrenList); Setter appender = childrenList.insertAfter(-1); for (Iterator i = ch.iterator(); i.hasNext();) { Node node = nodalize(i.next(), factory); appender.setNode(node); } } return elementNode; } /* * (non-Javadoc) * * @see org.nodal.filesystem.DocumentFormat.Decoder#setURI(java.lang.String) */ public String setURI(String uri) { source.setSystemId(uri); return uri; } /* * (non-Javadoc) * * @see org.nodal.filesystem.DocumentFormat.Decoder#exceptions() */ public List exceptions() { return exceptions; } } } |