1 /*
2  * Copyright (C) 2010 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package benchmarks;
18 
19 import com.google.caliper.BeforeExperiment;
20 import com.google.caliper.Param;
21 import java.io.ByteArrayInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.lang.reflect.Constructor;
26 import java.util.Arrays;
27 import java.util.List;
28 import javax.xml.parsers.DocumentBuilder;
29 import javax.xml.parsers.DocumentBuilderFactory;
30 import javax.xml.parsers.SAXParser;
31 import javax.xml.parsers.SAXParserFactory;
32 import org.w3c.dom.Document;
33 import org.w3c.dom.Node;
34 import org.xml.sax.Attributes;
35 import org.xml.sax.SAXException;
36 import org.xml.sax.helpers.DefaultHandler;
37 import org.xmlpull.v1.XmlPullParser;
38 
39 public class XmlParseBenchmark {
40 
41     @Param String xmlFile;
42     ByteArrayInputStream inputStream;
43 
44     static List<String> xmlFileValues = Arrays.asList(
45             "/etc/apns-conf.xml",
46             "/etc/media_profiles.xml",
47             "/etc/permissions/features.xml"
48     );
49 
50     private SAXParser saxParser;
51     private DocumentBuilder documentBuilder;
52     private Constructor<? extends XmlPullParser> kxmlConstructor;
53     private Constructor<? extends XmlPullParser> expatConstructor;
54 
55     @SuppressWarnings("unchecked")
56     @BeforeExperiment
setUp()57     protected void setUp() throws Exception {
58         byte[] xmlBytes = getXmlBytes();
59         inputStream = new ByteArrayInputStream(xmlBytes);
60         inputStream.mark(xmlBytes.length);
61 
62         SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
63         saxParser = saxParserFactory.newSAXParser();
64 
65         DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
66         documentBuilder = builderFactory.newDocumentBuilder();
67 
68         kxmlConstructor = (Constructor) Class.forName("com.android.org.kxml2.io.KXmlParser")
69                 .getConstructor();
70         expatConstructor = (Constructor) Class.forName("org.apache.harmony.xml.ExpatPullParser")
71                 .getConstructor();
72     }
73 
getXmlBytes()74     private byte[] getXmlBytes() throws IOException {
75         FileInputStream fileIn = new FileInputStream(xmlFile);
76         ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
77         int count;
78         byte[] buffer = new byte[1024];
79         while ((count = fileIn.read(buffer)) != -1) {
80             bytesOut.write(buffer, 0, count);
81         }
82         fileIn.close();
83         return bytesOut.toByteArray();
84     }
85 
timeSax(int reps)86     public int timeSax(int reps) throws IOException, SAXException {
87         int elementCount = 0;
88         for (int i = 0; i < reps; i++) {
89             inputStream.reset();
90             ElementCounterSaxHandler elementCounterSaxHandler = new ElementCounterSaxHandler();
91             saxParser.parse(inputStream, elementCounterSaxHandler);
92             elementCount += elementCounterSaxHandler.elementCount;
93         }
94         return elementCount;
95     }
96 
97     private static class ElementCounterSaxHandler extends DefaultHandler {
98         int elementCount = 0;
startElement(String uri, String localName, String qName, Attributes attributes)99         @Override public void startElement(String uri, String localName,
100                 String qName, Attributes attributes) {
101             elementCount++;
102         }
103     }
104 
timeDom(int reps)105     public int timeDom(int reps) throws IOException, SAXException {
106         int elementCount = 0;
107         for (int i = 0; i < reps; i++) {
108             inputStream.reset();
109             Document document = documentBuilder.parse(inputStream);
110             elementCount += countDomElements(document.getDocumentElement());
111         }
112         return elementCount;
113     }
114 
countDomElements(Node node)115     private int countDomElements(Node node) {
116         int result = 0;
117         for (; node != null; node = node.getNextSibling()) {
118             if (node.getNodeType() == Node.ELEMENT_NODE) {
119                 result++;
120             }
121             result += countDomElements(node.getFirstChild());
122         }
123         return result;
124     }
125 
timeExpat(int reps)126     public int timeExpat(int reps) throws Exception {
127         return testXmlPull(expatConstructor, reps);
128     }
129 
timeKxml(int reps)130     public int timeKxml(int reps) throws Exception {
131         return testXmlPull(kxmlConstructor, reps);
132     }
133 
testXmlPull(Constructor<? extends XmlPullParser> constructor, int reps)134     private int testXmlPull(Constructor<? extends XmlPullParser> constructor, int reps)
135             throws Exception {
136         int elementCount = 0;
137         for (int i = 0; i < reps; i++) {
138             inputStream.reset();
139             XmlPullParser xmlPullParser = constructor.newInstance();
140             xmlPullParser.setInput(inputStream, "UTF-8");
141             int type;
142             while ((type = xmlPullParser.next()) != XmlPullParser.END_DOCUMENT) {
143                 if (type == XmlPullParser.START_TAG) {
144                     elementCount++;
145                 }
146             }
147         }
148         return elementCount;
149     }
150 }
151