+++ /dev/null
-/*--------------------------------------------------------------------------\r
- * Copyright 2009 Taro L. Saito\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- *--------------------------------------------------------------------------*/\r
-//--------------------------------------\r
-// XerialJ\r
-//\r
-// DOMWalker.java\r
-// Since: 2009/03/30 23:39:34\r
-//\r
-// $URL$\r
-// $Author$\r
-//--------------------------------------\r
-package org.xerial.util.xml;\r
-\r
-import org.w3c.dom.Element;\r
-import org.w3c.dom.NamedNodeMap;\r
-import org.w3c.dom.Node;\r
-import org.w3c.dom.NodeList;\r
-import org.xerial.core.XerialError;\r
-import org.xerial.core.XerialErrorCode;\r
-import org.xerial.core.XerialException;\r
-import org.xerial.util.ArrayDeque;\r
-import org.xerial.util.Deque;\r
-import org.xerial.util.tree.TreeEvent;\r
-import org.xerial.util.tree.TreeStreamReader;\r
-import org.xerial.util.xml.dom.DOMUtil;\r
-import org.xerial.util.xml.impl.TreeEventQueue;\r
-\r
-/**\r
- * Stream walker for DOM data\r
- * \r
- * @author leo\r
- * \r
- */\r
-public class DOMStreamReader implements TreeStreamReader\r
-{\r
- private TreeEventQueue eventQueue = new TreeEventQueue();\r
- private Deque<Context> contextStack = new ArrayDeque<Context>();\r
-\r
- private static class Context\r
- {\r
- Element element;\r
- private int childCursor = -1;\r
- private boolean hasVisited = false;\r
- private boolean hasFinished = false;\r
-\r
- private Context(Element element)\r
- {\r
- this.element = element;\r
- }\r
-\r
- public boolean hasVisited()\r
- {\r
- return hasVisited;\r
- }\r
-\r
- public boolean hasFinished()\r
- {\r
- return hasFinished;\r
- }\r
-\r
- public void setFinished()\r
- {\r
- hasFinished = true;\r
- }\r
-\r
- public void setVisited()\r
- {\r
- hasVisited = true;\r
- }\r
-\r
- public boolean hasNextChild()\r
- {\r
- return childCursor + 1 < element.getChildNodes().getLength();\r
- }\r
-\r
- public Node nextChild()\r
- {\r
- childCursor++;\r
- NodeList nodeList = element.getChildNodes();\r
- if (childCursor >= nodeList.getLength())\r
- throw new XerialError(XerialErrorCode.INVALID_STATE, String.format(\r
- "childCursor=%d, nodeList.length=%d", childCursor, nodeList.getLength()));\r
- else\r
- {\r
- Node childNode = nodeList.item(childCursor);\r
- return childNode;\r
- }\r
-\r
- }\r
- }\r
-\r
- public DOMStreamReader(Element element)\r
- {\r
- contextStack.addLast(new Context(element));\r
- }\r
-\r
- public TreeEvent peekNext() throws XerialException\r
- {\r
- if (!eventQueue.isEmpty())\r
- {\r
- return eventQueue.peekFirst();\r
- }\r
-\r
- if (contextStack.isEmpty())\r
- return null;\r
-\r
- if (!contextStack.isEmpty())\r
- {\r
- Context context = contextStack.getLast();\r
- if (context.hasFinished())\r
- {\r
- contextStack.removeLast();\r
- return peekNext();\r
- }\r
- parse(context);\r
- }\r
-\r
- return peekNext();\r
- }\r
-\r
- public TreeEvent next() throws XerialException\r
- {\r
- if (!eventQueue.isEmpty())\r
- return eventQueue.pop();\r
-\r
- if (contextStack.isEmpty())\r
- return null;\r
-\r
- if (!contextStack.isEmpty())\r
- {\r
- Context context = contextStack.getLast();\r
- if (context.hasFinished())\r
- {\r
- contextStack.removeLast();\r
- return next();\r
- }\r
- parse(context);\r
- }\r
-\r
- return next();\r
- }\r
-\r
- public void parse(Context context)\r
- {\r
- if (!context.hasVisited())\r
- {\r
- context.setVisited();\r
-\r
- Element currentElement = context.element;\r
- String tagName = currentElement.getNodeName();\r
- // invoke visitor\r
- String text = DOMUtil.getText(currentElement);\r
-\r
- Deque<TreeEvent> subEventQueue = new ArrayDeque<TreeEvent>();\r
-\r
- String nodeValue = null;\r
- // visit attribute nodes\r
- NamedNodeMap attributeMap = currentElement.getAttributes();\r
- for (int i = 0; i < attributeMap.getLength(); i++)\r
- {\r
- Node attributeNode = attributeMap.item(i);\r
- String attributeName = attributeNode.getNodeName();\r
- String attributeValue = attributeNode.getNodeValue();\r
-\r
- if (attributeName.equals("value"))\r
- {\r
- nodeValue = attributeValue;\r
- continue;\r
- }\r
-\r
- subEventQueue.addLast(TreeEvent.newVisitEvent(attributeName, attributeValue));\r
- subEventQueue.addLast(TreeEvent.newLeaveEvent(attributeName));\r
- }\r
-\r
- if (text != null)\r
- {\r
- text = text.trim();\r
- if (text.length() <= 0)\r
- text = null;\r
- }\r
-\r
- if (nodeValue != null)\r
- {\r
- subEventQueue.addFirst(TreeEvent.newVisitEvent(tagName, nodeValue));\r
- if (text != null)\r
- subEventQueue.addLast(TreeEvent.newTextEvent(tagName, text));\r
- }\r
- else\r
- {\r
- subEventQueue.addFirst(TreeEvent.newVisitEvent(tagName, text));\r
- }\r
-\r
- eventQueue.push(subEventQueue);\r
- }\r
-\r
- for (;;)\r
- {\r
- if (context.hasNextChild())\r
- {\r
- Node childNode = context.nextChild();\r
- if (childNode.getNodeType() == Node.ELEMENT_NODE)\r
- {\r
- contextStack.addLast(new Context((Element) childNode));\r
- break;\r
- }\r
- else\r
- continue;\r
- }\r
- else\r
- {\r
- context.setFinished();\r
- eventQueue.push(TreeEvent.newLeaveEvent(context.element.getNodeName()));\r
- break;\r
- }\r
- }\r
-\r
- }\r
-}\r