1 package org.robolectric.res; 2 3 import java.nio.file.Path; 4 import java.util.ArrayDeque; 5 import java.util.Deque; 6 import javax.xml.stream.XMLInputFactory; 7 import javax.xml.stream.XMLStreamConstants; 8 import javax.xml.stream.XMLStreamException; 9 import javax.xml.stream.XMLStreamReader; 10 11 public class StaxDocumentLoader extends DocumentLoader { 12 private static final NodeHandler NO_OP_HANDLER = new NodeHandler(); 13 14 private final NodeHandler topLevelNodeHandler; 15 private final XMLInputFactory factory; 16 StaxDocumentLoader( String packageName, Path resourceBase, NodeHandler topLevelNodeHandler)17 public StaxDocumentLoader( 18 String packageName, Path resourceBase, NodeHandler topLevelNodeHandler) { 19 super(packageName, resourceBase); 20 21 this.topLevelNodeHandler = topLevelNodeHandler; 22 factory = XMLInputFactory.newFactory(); 23 } 24 25 @Override loadResourceXmlFile(XmlContext xmlContext)26 protected void loadResourceXmlFile(XmlContext xmlContext) { 27 Path xmlFile = xmlContext.getXmlFile(); 28 29 XMLStreamReader xmlStreamReader; 30 try { 31 xmlStreamReader = factory.createXMLStreamReader(Fs.getInputStream(xmlFile)); 32 doParse(xmlStreamReader, xmlContext); 33 } catch (Exception e) { 34 throw new RuntimeException("error parsing " + xmlFile, e); 35 } 36 if (xmlStreamReader != null) { 37 try { 38 xmlStreamReader.close(); 39 } catch (XMLStreamException e) { 40 throw new RuntimeException(e); 41 } 42 } 43 } 44 doParse(XMLStreamReader reader, XmlContext xmlContext)45 protected void doParse(XMLStreamReader reader, XmlContext xmlContext) throws XMLStreamException { 46 NodeHandler nodeHandler = this.topLevelNodeHandler; 47 Deque<NodeHandler> nodeHandlerStack = new ArrayDeque<>(); 48 49 while (reader.hasNext()) { 50 int event = reader.next(); 51 switch (event) { 52 case XMLStreamConstants.START_DOCUMENT: 53 break; 54 55 case XMLStreamConstants.START_ELEMENT: 56 nodeHandlerStack.push(nodeHandler); 57 NodeHandler elementHandler = nodeHandler.findMatchFor(reader); 58 nodeHandler = elementHandler == null ? NO_OP_HANDLER : elementHandler; 59 nodeHandler.onStart(reader, xmlContext); 60 break; 61 62 case XMLStreamConstants.CDATA: 63 case XMLStreamConstants.CHARACTERS: 64 nodeHandler.onCharacters(reader, xmlContext); 65 break; 66 67 case XMLStreamConstants.END_ELEMENT: 68 nodeHandler.onEnd(reader, xmlContext); 69 nodeHandler = nodeHandlerStack.pop(); 70 break; 71 72 case XMLStreamConstants.ATTRIBUTE: 73 } 74 } 75 } 76 } 77