/* * Freeplane - mind map editor * Copyright (C) 2008 Dimitry Polivaev * * This file author is Dimitry Polivaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.freeplane.core.io.xml; import java.awt.Point; import java.io.Reader; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.StringTokenizer; import org.freeplane.core.io.IAttributeHandler; import org.freeplane.core.io.IElementContentHandler; import org.freeplane.core.io.IElementDOMHandler; import org.freeplane.core.io.IElementHandler; import org.freeplane.core.io.ListHashTable; import org.freeplane.core.io.ReadManager; import org.freeplane.n3.nanoxml.IXMLBuilder; import org.freeplane.n3.nanoxml.IXMLReader; import org.freeplane.n3.nanoxml.NonValidator; import org.freeplane.n3.nanoxml.StdXMLReader; import org.freeplane.n3.nanoxml.XMLElement; import org.freeplane.n3.nanoxml.XMLException; public class TreeXmlReader implements IXMLBuilder { public static boolean xmlToBoolean(final String string) { if (string == null) { return false; } if (string.equals("true")) { return true; } return false; } /** * Extracts a long from xml. Only useful for dates. */ public static Date xmlToDate(final String xmlString) { try { return new Date(Long.valueOf(xmlString).longValue()); } catch (final Exception e) { return new Date(System.currentTimeMillis()); } } public static Point xmlToPoint(String string) { if (string == null) { return null; } if (string.startsWith("java.awt.Point")) { string = string.replaceAll("java\\.awt\\.Point\\[x=(-?[0-9]+),y=(-?[0-9]+)\\]", "$1;$2"); } final StringTokenizer tok = new StringTokenizer(string, ";"); if (tok.countTokens() != 2) { throw new IllegalArgumentException("A point must consist of two numbers (and not: '" + string + "')."); } final int x = Integer.parseInt(tok.nextToken()); final int y = Integer.parseInt(tok.nextToken()); return new Point(x, y); } private Hashtable<String, IAttributeHandler> attributeHandlersForTag; private Object currentElement; private String elementContentAsString; final private LinkedList<Object> elementStack = new LinkedList<Object>(); private IElementHandler nodeCreator; final private LinkedList<IElementHandler> nodeCreatorStack = new LinkedList<IElementHandler>(); private Object parentElement; final private ReadManager parseManager; private XMLParser parser; private XMLElement saveAsXmlUntil; private String tag; private StdXMLBuilder xmlBuilder; public TreeXmlReader(final ReadManager parseManager) { super(); this.parseManager = parseManager; } private boolean addAttribute(final String key, final String value) { if (saveAsXmlUntil == null && attributeHandlersForTag != null) { final IAttributeHandler attributeHandler = attributeHandlersForTag.get(key); if (attributeHandler != null) { attributeHandler.setAttribute(currentElement, value); return true; } } return false; } /* * (non-Javadoc) * @see * freeplane.persistence.xml.n3.nanoxml.IXMLBuilder#addAttribute(java.lang * .String, java.lang.String, java.lang.String, java.lang.String, * java.lang.String) */ public void addAttribute(final String key, final String nsPrefix, final String nsURI, final String value, final String type) throws Exception { if (!addAttribute(key, value)) { xmlBuilder.addAttribute(key, nsPrefix, nsURI, value, type); } } /* * (non-Javadoc) * @see * freeplane.persistence.xml.n3.nanoxml.IXMLBuilder#addPCData(java.io.Reader * , java.lang.String, int) */ public void addPCData(final Reader reader, final String systemID, final int lineNr) throws Exception { xmlBuilder.addPCData(reader, systemID, lineNr); } /* * (non-Javadoc) * @see * freeplane.persistence.xml.n3.nanoxml.IXMLBuilder#elementAttributesProcessed * (java.lang.String, java.lang.String, java.lang.String) */ public void elementAttributesProcessed(final String name, final String nsPrefix, final String nsURI) throws Exception { xmlBuilder.elementAttributesProcessed(name, nsPrefix, nsURI); if (saveAsXmlUntil != null || nodeCreator != null) { return; } final Iterator<IElementHandler> iterator = getElementHandlers().iterator(tag); final XMLElement lastBuiltElement = xmlBuilder.getLastBuiltElement(); while (iterator.hasNext() && currentElement == null) { nodeCreator = iterator.next(); currentElement = nodeCreator.createElement(parentElement, name, lastBuiltElement); } if (currentElement != null) { if (nodeCreator instanceof IElementContentHandler) { parser.notParseNextElementContent(); } attributeHandlersForTag = getAttributeLoaders().get(tag); if (attributeHandlersForTag == null) { return; } final Enumeration<String> attributeNames = lastBuiltElement.enumerateAttributeNames(); while (attributeNames.hasMoreElements()) { final String atName = (String) attributeNames.nextElement(); if (addAttribute(atName, lastBuiltElement.getAttribute(atName, null))) { lastBuiltElement.removeAttribute(atName); } } } else { currentElement = null; nodeCreator = null; saveAsXmlUntil = lastBuiltElement; } } /* * (non-Javadoc) * @see * freeplane.persistence.xml.n3.nanoxml.IXMLBuilder#endElement(java.lang * .String, java.lang.String, java.lang.String) */ public void endElement(final String name, final String nsPrefix, final String nsURI) throws Exception { final XMLElement lastBuiltElement = xmlBuilder.getParentElement(); xmlBuilder.endElement(name, nsPrefix, nsURI); if (saveAsXmlUntil == lastBuiltElement) { saveAsXmlUntil = null; } if (saveAsXmlUntil != null) { return; } tag = null; if (0 == elementStack.size()) { return; } final Object element = currentElement; currentElement = elementStack.removeLast(); if (nodeCreator instanceof IElementContentHandler) { ((IElementContentHandler) nodeCreator).endElement(currentElement, name, element, lastBuiltElement, elementContentAsString); } else if (nodeCreator instanceof IElementDOMHandler) { ((IElementDOMHandler) nodeCreator).endElement(currentElement, name, element, lastBuiltElement); } final XMLElement top = lastBuiltElement.getParent(); if (nodeCreator != null && top != null && top.hasChildren()) { final int lastChildIndex = top.getChildrenCount() - 1; top.removeChildAtIndex(lastChildIndex); } nodeCreator = (IElementHandler) nodeCreatorStack.removeLast(); elementContentAsString = null; } private Hashtable<String, Hashtable<String, IAttributeHandler>> getAttributeLoaders() { return parseManager.getAttributeHandlers(); } private ListHashTable<String, IElementHandler> getElementHandlers() { return parseManager.getElementHandlers(); } /* * (non-Javadoc) * @see freeplane.persistence.xml.n3.nanoxml.IXMLBuilder#getResult() */ public Object getResult() throws Exception { return null; } /* * (non-Javadoc) * @see freeplane.persistence.Reader#load() */ public void load(final Reader reader) throws XMLException { parser = new XMLParser(); final IXMLReader nanoxmlReader = new StdXMLReader(reader); parser.setReader(nanoxmlReader); parser.setBuilder(this); parser.setValidator(new NonValidator()); parser.parse(); } /* * (non-Javadoc) * @see * freeplane.persistence.xml.n3.nanoxml.IXMLBuilder#newProcessingInstruction * (java.lang.String, java.io.Reader) */ public void newProcessingInstruction(final String target, final Reader reader) throws Exception { xmlBuilder.newProcessingInstruction(target, reader); } private void pushParentObjects() { elementStack.addLast(currentElement); nodeCreatorStack.addLast(nodeCreator); } /** */ public void setElementContent(final String content) { elementContentAsString = content; } /* * (non-Javadoc) * @see * freeplane.persistence.xml.n3.nanoxml.IXMLBuilder#startBuilding(java.lang * .String, int) */ public void startBuilding(final String systemID, final int lineNr) throws Exception { xmlBuilder = new StdXMLBuilder(); xmlBuilder.startBuilding(systemID, lineNr); saveAsXmlUntil = null; } /* * (non-Javadoc) * @see * freeplane.persistence.xml.n3.nanoxml.IXMLBuilder#startElement(java.lang * .String, java.lang.String, java.lang.String, java.lang.String, int) */ public void startElement(final String name, final String nsPrefix, final String nsURI, final String systemID, final int lineNr) throws Exception { if (saveAsXmlUntil != null) { xmlBuilder.startElement(name, nsPrefix, nsURI, systemID, lineNr); return; } xmlBuilder.startElement(name, nsPrefix, nsURI, systemID, lineNr); tag = name; pushParentObjects(); parentElement = currentElement; currentElement = null; final List<IElementHandler> handlers = getElementHandlers().list(tag); if (handlers != null && handlers.size() == 1) { nodeCreator = handlers.get(0); currentElement = nodeCreator.createElement(parentElement, tag, null); } if (currentElement != null) { attributeHandlersForTag = getAttributeLoaders().get(tag); if (nodeCreator instanceof IElementContentHandler) { parser.notParseNextElementContent(); } } else { attributeHandlersForTag = null; currentElement = null; nodeCreator = null; } } public void load(Object currentElement, Reader pReader) throws XMLException { this.currentElement = currentElement; load(pReader); } }