001 /*
002 * Copyright 2009 - 2010 JEuclid, http://jeuclid.sf.net
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 /* $Id $ */
018
019 package net.sourceforge.jeuclid.biparser;
020
021 import java.util.ArrayList;
022 import java.util.List;
023
024 import net.sourceforge.jeuclid.elements.JEuclidElementFactory;
025
026 import org.xml.sax.Attributes;
027 import org.xml.sax.SAXParseException;
028
029 /**
030 * this class if for creating a BiTree with ABiNodes while parsing a text.
031 *
032 * @version $Revision: 0b66106c7ff7 $
033 */
034 public class BiTreeCreationHelper {
035
036 /** current position in tree. */
037 private IBiNode currentBiNode;
038 /** root of tree. */
039 private IBiNode root;
040 /** save positions of open tags. */
041 private final List<Integer> startPositions;
042
043 /**
044 * create a new BiTreeHelper. get result (tree of ABiNodes) with getRoot()
045 */
046 public BiTreeCreationHelper() {
047 this.startPositions = new ArrayList<Integer>();
048 }
049
050 /**
051 * get root of BiTree.
052 *
053 * @return root of BiTree
054 */
055 public final IBiNode getRoot() {
056 return this.root;
057 }
058
059 /**
060 * create and append a new BiNode at current position in BiTree.
061 *
062 * @param totalOffset
063 * of node in text
064 * @param childOffset
065 * position of first child (length of open tag)
066 * @param namespaceURI
067 * namespace
068 * @param eName
069 * name of node
070 * @param attrs
071 * attributes of node
072 * @throws SAXParseException
073 * if the element cannot be recognized by JEuclid.
074 */
075 public final void createBiNode(final int totalOffset,
076 final int childOffset, final String namespaceURI,
077 final String eName, final Attributes attrs) throws SAXParseException {
078
079 if (JEuclidElementFactory.getJEuclidElementConstructor(namespaceURI,
080 eName) == null) {
081 throw new NonIncrementalElementException(eName);
082 }
083 BiNode biNode;
084
085 this.startPositions.add(totalOffset);
086
087 // new root node
088 if (this.root == null) {
089 this.root = new BiNode(childOffset, namespaceURI, eName, attrs);
090 this.currentBiNode = this.root;
091 } else {
092 biNode = new BiNode(childOffset, namespaceURI, eName, attrs);
093
094 // append child (only possible at start
095 if (this.currentBiNode.getType() == BiType.EMPTY) {
096 this.currentBiNode.addSibling(biNode);
097 } else {
098 // add child (default case)
099 ((BiNode) this.currentBiNode).addChild(biNode);
100 }
101
102 this.currentBiNode = biNode;
103 }
104 }
105
106 /**
107 * close BiNode (set length of node).
108 *
109 * @param length
110 * length of node
111 */
112 public final void closeBiNode(final int length) {
113 BiNode parent;
114 final int last = this.startPositions.size() - 1;
115
116 this.currentBiNode.setLength(length - this.startPositions.get(last));
117
118 // move current position to parent
119 parent = this.currentBiNode.getParent();
120 if (parent != null) {
121 this.currentBiNode = parent;
122 }
123
124 this.startPositions.remove(last);
125 }
126
127 /**
128 * check if current position in BiTree allows a TextNode as child.
129 *
130 * @return true if a TextNode is allowed
131 */
132 public final boolean allowNewTextNode() {
133 return ((BiNode) this.currentBiNode).getChild() == null;
134 }
135
136 /**
137 * create a new TextNode at current position.
138 *
139 * @param length
140 * length of TextNode
141 * @param t
142 * text of TextNode
143 */
144 public final void createTextNode(final int length, final String t) {
145 ((BiNode) this.currentBiNode).addChild(new TextNode(length, t));
146 }
147
148 /**
149 * create a new EmptyNode at current position in BiTree.
150 *
151 * @param length
152 * length of EmtpyNode
153 */
154 public final void createEmtpyNode(final int length) {
155 // EmptyNode is new root
156 if (this.root == null) {
157 this.root = new EmptyNode(length);
158 this.currentBiNode = this.root;
159 } else {
160 ((BiNode) this.currentBiNode).addChild(new EmptyNode(length));
161 }
162 }
163 }