]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/java/org/opensrf/util/XMLFlattener.java
LP1827055 Remove Python libs, install bits, and docs
[OpenSRF.git] / src / java / org / opensrf / util / XMLFlattener.java
1 package org.opensrf.util;
2
3 import javax.xml.stream.*;
4 import javax.xml.stream.events.* ;
5 import javax.xml.namespace.QName;
6 import java.util.Map;
7 import java.util.HashMap;
8 import java.util.List;
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;
14
15 /**
16  * Flattens an XML file into a properties map.  Values are stored as JSON strings or arrays.
17  * An array is created if more than one value resides at the same key.
18  * e.g. html.head.script = "alert('hello');"
19  */
20 public class XMLFlattener {
21
22     /** Flattened properties map */
23     private Map<String, String> props;
24     /** Incoming XML stream */
25     private InputStream inStream;
26     /** Runtime list of encountered elements */
27     private List<String> elementList;
28
29     /**
30      * Creates a new reader. Initializes the message queue.
31      * Sets the stream state to disconnected, and the xml
32      * state to in_nothing.
33      * @param inStream the inbound XML stream
34      */
35     public XMLFlattener(InputStream inStream) {
36         props = new HashMap<String, String>();
37         this.inStream = inStream;
38         elementList = new ArrayList<String>();
39     }
40
41     /** Turns an array of strings into a dot-separated key string */
42     private String listToString() {
43         ListIterator itr = elementList.listIterator();
44         StringBuffer sb = new StringBuffer();
45         while(itr.hasNext()) {
46             sb.append(itr.next());
47             if(itr.hasNext())
48                 sb.append(".");
49         }
50         return sb.toString();
51     }
52
53     /**
54      * Parses XML data from the provided stream.
55      */
56     public Map read() throws javax.xml.stream.XMLStreamException {
57
58         XMLInputFactory factory = XMLInputFactory.newInstance();
59
60         /** disable as many unused features as possible to speed up the parsing */
61         factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, Boolean.TRUE);
62         factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
63         factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
64         factory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.FALSE);
65         factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
66
67         /** create the stream reader */
68         XMLStreamReader reader = factory.createXMLStreamReader(inStream);
69         int eventType;
70
71         while(reader.hasNext()) {
72             /** cycle through the XML events */
73
74             eventType = reader.next();
75             if(reader.isWhiteSpace()) continue;
76
77             switch(eventType) {
78
79                 case XMLEvent.START_ELEMENT:
80                     elementList.add(reader.getName().toString());
81                     break;
82
83                 case XMLEvent.CHARACTERS:
84                     String text = reader.getText();
85                     String key = listToString();
86
87                     if(props.containsKey(key)) {
88
89                         /* something in the map already has this key */
90
91                         Object o = null;
92                         try {
93                             o = new JSONReader(props.get(key)).read();
94                         } catch(org.opensrf.util.JSONException e){}
95
96                         if(o instanceof List) {
97                             /* if the map contains a list, append to the list and re-encode */
98                             ((List) o).add(text);
99
100                         } else {
101                             /* if the map just contains a string, start building a new list
102                              * with the old string and append the new string */
103                             List<String> arr = new ArrayList<String>();
104                             arr.add((String) o);
105                             arr.add(text);
106                             o = arr;
107                         }
108
109                         props.put(key, new JSONWriter(o).write());
110
111                     } else {
112                         props.put(key, new JSONWriter(text).write());
113                     }
114                     break;
115
116                 case XMLEvent.END_ELEMENT: 
117                     elementList.remove(elementList.size()-1);
118                     break;
119             }
120         }
121
122         return props;
123     }
124 }
125
126
127
128