1 package org.opensrf.util;
3 import javax.xml.stream.*;
4 import javax.xml.stream.events.* ;
5 import javax.xml.namespace.QName;
7 import java.util.HashMap;
9 import java.util.ArrayList;
10 import java.util.ListIterator;
11 import java.io.InputStream;
12 import org.opensrf.util.JSONWriter;
13 import org.opensrf.util.JSONReader;
15 import com.ctc.wstx.stax.WstxInputFactory;
18 * Flattens an XML file into a properties map. Values are stored as JSON strings or arrays.
19 * An array is created if more than one value resides at the same key.
20 * e.g. html.head.script = "alert('hello');"
22 public class XMLFlattener {
24 /** Flattened properties map */
25 private Map<String, String> props;
26 /** Incoming XML stream */
27 private InputStream inStream;
28 /** Runtime list of encountered elements */
29 private List<String> elementList;
32 * Creates a new reader. Initializes the message queue.
33 * Sets the stream state to disconnected, and the xml
34 * state to in_nothing.
35 * @param inStream the inbound XML stream
37 public XMLFlattener(InputStream inStream) {
38 props = new HashMap<String, String>();
39 this.inStream = inStream;
40 elementList = new ArrayList<String>();
43 /** Turns an array of strings into a dot-separated key string */
44 private String listToString() {
45 ListIterator itr = elementList.listIterator();
46 StringBuffer sb = new StringBuffer();
47 while(itr.hasNext()) {
48 sb.append(itr.next());
56 * Parses XML data from the provided stream.
58 public Map read() throws javax.xml.stream.XMLStreamException {
60 //XMLInputFactory factory = XMLInputFactory.newInstance();
61 XMLInputFactory factory = new com.ctc.wstx.stax.WstxInputFactory();
63 /** disable as many unused features as possible to speed up the parsing */
64 factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, Boolean.TRUE);
65 factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
66 factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
67 factory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.FALSE);
68 factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
70 /** create the stream reader */
71 XMLStreamReader reader = factory.createXMLStreamReader(inStream);
74 while(reader.hasNext()) {
75 /** cycle through the XML events */
77 eventType = reader.next();
78 if(reader.isWhiteSpace()) continue;
82 case XMLEvent.START_ELEMENT:
83 elementList.add(reader.getName().toString());
86 case XMLEvent.CHARACTERS:
87 String text = reader.getText();
88 String key = listToString();
90 if(props.containsKey(key)) {
92 /* something in the map already has this key */
96 o = new JSONReader(props.get(key)).read();
97 } catch(org.opensrf.util.JSONException e){}
99 if(o instanceof List) {
100 /* if the map contains a list, append to the list and re-encode */
101 ((List) o).add(text);
104 /* if the map just contains a string, start building a new list
105 * with the old string and append the new string */
106 List<String> arr = new ArrayList<String>();
112 props.put(key, new JSONWriter(o).write());
115 props.put(key, new JSONWriter(text).write());
119 case XMLEvent.END_ELEMENT:
120 elementList.remove(elementList.size()-1);