/** * Copyright 2015 Santhosh Kumar Tekuri * * The JLibs authors license this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package jlibs.xml.sax.dog.sniff; import jlibs.xml.sax.dog.NodeItem; import jlibs.xml.sax.dog.NodeType; import jlibs.xml.sax.helpers.MyNamespaceSupport; import org.xml.sax.Attributes; import javax.xml.stream.XMLStreamReader; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.List; /** * @author Santhosh Kumar T */ public abstract class XMLBuilder{ // changed to true by Event in onStartDocument/onStartElement if current event is hit // changed to false by doEndElement() when curNode is completely populated // keeps changing values true <-> false, so that nodes are created only portions of xml boolean active = false; protected abstract Object onStartDocument(); Object doStartDocument(NodeItem nodeItem){ stack.add(nodeItem); return onStartDocument(); } protected abstract Object onStartElement(Event event); Object doStartElement(Event event, NodeItem nodeItem){ stack.add(nodeItem); return onStartElement(event); } protected abstract Object onEvent(Event event); protected abstract Object onEndElement(); Object doEndElement(Event event){ assert active; NodeItem finishedNode = stack.remove(stack.size()-1); if(finishedNode!=null) event.finishedXMLBuild(finishedNode); Object node = onEndElement(); if(node==null) active = false; return node; } protected abstract void onEndDocument(); void doEndDocument(Event event){ if(!stack.isEmpty()){ NodeItem finishedNode = stack.remove(stack.size()-1); if(finishedNode!=null) event.finishedXMLBuild(finishedNode); } stack = null; onEndDocument(); } public void onAttributes(Event event, Attributes attrs){ assert active; int len = attrs.getLength(); for(int i=0; i<len; i++){ event.setData(NodeType.ATTRIBUTE, attrs.getURI(i), attrs.getLocalName(i), attrs.getQName(i), attrs.getValue(i)); onEvent(event); } } public void onAttributes(Event event, XMLStreamReader reader){ assert active; int len = reader.getAttributeCount(); for(int i=0; i<len; i++){ String prefix = reader.getAttributePrefix(i); String localName = reader.getAttributeLocalName(i); String qname = prefix.length()==0 ? localName : prefix+':'+localName; String uri = reader.getAttributeNamespace(i); if(uri==null) uri = ""; event.setData(NodeType.ATTRIBUTE, uri, localName, qname, reader.getAttributeValue(i)); onEvent(event); } } public void onNamespaces(Event event, MyNamespaceSupport nsSupport){ assert active; Enumeration<String> prefixes = hasParent() ? nsSupport.getDeclaredPrefixes() : nsSupport.getPrefixes(); while(prefixes.hasMoreElements()){ String prefix = prefixes.nextElement(); String uri = nsSupport.getURI(prefix); event.setData(NodeType.NAMESPACE, "", prefix, prefix, uri); onEvent(event); } } private List<NodeItem> stack = new ArrayList<NodeItem>(); void discard(long order){ Iterator<NodeItem> iter = stack.iterator(); boolean first = true; while(iter.hasNext()){ NodeItem nodeItem = iter.next(); if(nodeItem!=null){ if(nodeItem.order==order){ if(--nodeItem.refCount>0) // no xml to be dicarded return; if(first){ /* detach from first decendant nodeitem */ nodeItem.xml = null; while(iter.hasNext()){ nodeItem = iter.next(); if(nodeItem!=null){ if(nodeItem.xml!=null) removeFromParent(nodeItem.xml); return; } } /* comes here only when no descendant nodeitem was there */ clearCurNode(); active = false; } return; } first = false; } } } protected abstract void clearCurNode(); protected abstract void removeFromParent(Object node); protected abstract boolean hasParent(); }