diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index ced763841..4e4ccef18 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -28,13 +28,14 @@ import android.util.Xml;
 import com.android.inputmethod.keyboard.internal.KeyStyles;
 import com.android.inputmethod.keyboard.internal.KeyStyles.KeyStyle;
 import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
-import com.android.inputmethod.keyboard.internal.KeyboardBuilder.ParseException;
 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
 import com.android.inputmethod.keyboard.internal.KeyboardParams;
 import com.android.inputmethod.keyboard.internal.MoreKeySpecParser;
+import com.android.inputmethod.keyboard.internal.XmlParseUtils;
 import com.android.inputmethod.latin.R;
 
 import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -212,9 +213,10 @@ public class Key {
      *        this key.
      * @param parser the XML parser containing the attributes for this key
      * @param keyStyles active key styles set
+     * @throws XmlPullParserException
      */
     public Key(Resources res, KeyboardParams params, KeyboardBuilder.Row row,
-            XmlPullParser parser, KeyStyles keyStyles) {
+            XmlPullParser parser, KeyStyles keyStyles) throws XmlPullParserException {
         final float horizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
         final int keyHeight = row.mRowHeight;
         mVerticalGap = params.mVerticalGap;
@@ -228,7 +230,8 @@ public class Key {
             String styleName = keyAttr.getString(R.styleable.Keyboard_Key_keyStyle);
             style = keyStyles.getKeyStyle(styleName);
             if (style == null)
-                throw new ParseException("Unknown key style: " + styleName, parser);
+                throw new XmlParseUtils.ParseException(
+                        "Unknown key style: " + styleName, parser);
         } else {
             style = KeyStyles.getEmptyKeyStyle();
         }
@@ -468,9 +471,9 @@ public class Key {
      * Detects if a point falls on this key.
      * @param x the x-coordinate of the point
      * @param y the y-coordinate of the point
-     * @return whether or not the point falls on the key. If the key is attached to an edge, it will
-     * assume that all points between the key and the edge are considered to be on the key.
-     * @see {@link #markAsLeftEdge(KeyboardParams)} etc.
+     * @return whether or not the point falls on the key. If the key is attached to an edge, it
+     * will assume that all points between the key and the edge are considered to be on the key.
+     * @see #markAsLeftEdge(KeyboardParams) etc.
      */
     public boolean isOnKey(int x, int y) {
         return mHitBox.contains(x, y);
@@ -569,7 +572,7 @@ public class Key {
 
     public static class Spacer extends Key {
         public Spacer(Resources res, KeyboardParams params, KeyboardBuilder.Row row,
-                XmlPullParser parser, KeyStyles keyStyles) {
+                XmlPullParser parser, KeyStyles keyStyles) throws XmlPullParserException {
             super(res, params, row, parser, keyStyles);
         }
 
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
index 0697c187e..9f182aff4 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
@@ -25,10 +25,7 @@ import android.util.DisplayMetrics;
 import android.util.Xml;
 import android.view.inputmethod.EditorInfo;
 
-import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
-import com.android.inputmethod.keyboard.internal.KeyboardBuilder.IllegalEndTag;
-import com.android.inputmethod.keyboard.internal.KeyboardBuilder.IllegalStartTag;
-import com.android.inputmethod.keyboard.internal.KeyboardBuilder.ParseException;
+import com.android.inputmethod.keyboard.internal.XmlParseUtils;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LocaleUtils;
 import com.android.inputmethod.latin.R;
@@ -172,7 +169,7 @@ public class KeyboardSet {
                         if (TAG_KEYBOARD_SET.equals(tag)) {
                             parseKeyboardSetContent(parser);
                         } else {
-                            throw new IllegalStartTag(parser, TAG_KEYBOARD_SET);
+                            throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET);
                         }
                     }
                 }
@@ -190,14 +187,14 @@ public class KeyboardSet {
                     if (TAG_ELEMENT.equals(tag)) {
                         parseKeyboardSetElement(parser);
                     } else {
-                        throw new IllegalStartTag(parser, TAG_KEYBOARD_SET);
+                        throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET);
                     }
                 } else if (event == XmlPullParser.END_TAG) {
                     final String tag = parser.getName();
                     if (TAG_KEYBOARD_SET.equals(tag)) {
                         break;
                     } else {
-                        throw new IllegalEndTag(parser, TAG_KEYBOARD_SET);
+                        throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEYBOARD_SET);
                     }
                 }
             }
@@ -208,15 +205,13 @@ public class KeyboardSet {
             final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
                     R.styleable.KeyboardSet_Element);
             try {
-                if (!a.hasValue(R.styleable.KeyboardSet_Element_elementName)) {
-                    throw new ParseException(
-                            "No elementName attribute in <" + TAG_ELEMENT + "/>", parser);
-                }
-                if (!a.hasValue(R.styleable.KeyboardSet_Element_elementKeyboard)) {
-                    throw new ParseException(
-                            "No elementKeyboard attribute in <" + TAG_ELEMENT + "/>", parser);
-                }
-                KeyboardBuilder.checkEndTag(TAG_ELEMENT, parser);
+                XmlParseUtils.checkAttributeExists(a,
+                        R.styleable.KeyboardSet_Element_elementName, "elementName",
+                        TAG_ELEMENT, parser);
+                XmlParseUtils.checkAttributeExists(a,
+                        R.styleable.KeyboardSet_Element_elementKeyboard, "elementKeyboard",
+                        TAG_ELEMENT, parser);
+                XmlParseUtils.checkEndTag(TAG_ELEMENT, parser);
 
                 final int elementName = a.getInt(
                         R.styleable.KeyboardSet_Element_elementName, 0);
@@ -245,7 +240,7 @@ public class KeyboardSet {
                     keyboardSetAttr.recycle();
                     return locale;
                 } else {
-                    throw new IllegalStartTag(parser, TAG_KEYBOARD_SET);
+                    throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET);
                 }
             }
         }
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
index 218793500..3324fa6af 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
@@ -19,10 +19,10 @@ package com.android.inputmethod.keyboard.internal;
 import android.content.res.TypedArray;
 import android.util.Log;
 
-import com.android.inputmethod.keyboard.internal.KeyboardBuilder.ParseException;
 import com.android.inputmethod.latin.R;
 
 import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -43,7 +43,7 @@ public class KeyStyles {
     }
 
     /* package */ static class EmptyKeyStyle implements KeyStyle {
-        private EmptyKeyStyle() {
+        EmptyKeyStyle() {
             // Nothing to do.
         }
 
@@ -118,7 +118,7 @@ public class KeyStyles {
         }
     }
 
-    private static class DeclaredKeyStyle extends EmptyKeyStyle {
+    /* package */ static class DeclaredKeyStyle extends EmptyKeyStyle {
         private final HashMap<Integer, Object> mAttributes = new HashMap<Integer, Object>();
 
         @Override
@@ -145,11 +145,11 @@ public class KeyStyles {
             return super.getFlag(a, index, defaultValue) | (value != null ? value : 0);
         }
 
-        private DeclaredKeyStyle() {
+        DeclaredKeyStyle() {
             super();
         }
 
-        private void parseKeyStyleAttributes(TypedArray keyAttr) {
+        void parseKeyStyleAttributes(TypedArray keyAttr) {
             // TODO: Currently not all Key attributes can be declared as style.
             readInt(keyAttr, R.styleable.Keyboard_Key_code);
             readInt(keyAttr, R.styleable.Keyboard_Key_altCode);
@@ -188,18 +188,19 @@ public class KeyStyles {
                 mAttributes.put(index, value);
         }
 
-        private void addParent(DeclaredKeyStyle parentStyle) {
+        void addParent(DeclaredKeyStyle parentStyle) {
             mAttributes.putAll(parentStyle.mAttributes);
         }
     }
 
     public void parseKeyStyleAttributes(TypedArray keyStyleAttr, TypedArray keyAttrs,
-            XmlPullParser parser) {
+            XmlPullParser parser) throws XmlPullParserException {
         final String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName);
         if (DEBUG) Log.d(TAG, String.format("<%s styleName=%s />",
                 KeyboardBuilder.TAG_KEY_STYLE, styleName));
         if (mStyles.containsKey(styleName))
-            throw new ParseException("duplicate key style declared: " + styleName, parser);
+            throw new XmlParseUtils.ParseException(
+                    "duplicate key style declared: " + styleName, parser);
 
         final DeclaredKeyStyle style = new DeclaredKeyStyle();
         if (keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) {
@@ -207,7 +208,8 @@ public class KeyStyles {
                     R.styleable.Keyboard_KeyStyle_parentStyle);
             final DeclaredKeyStyle parent = mStyles.get(parentStyle);
             if (parent == null)
-                throw new ParseException("Unknown parentStyle " + parentStyle, parser);
+                throw new XmlParseUtils.ParseException(
+                        "Unknown parentStyle " + parentStyle, parser);
             style.addParent(parent);
         }
         style.parseKeyStyleAttributes(keyAttrs);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index d9d9c2f83..a88a1638c 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -305,7 +305,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
                     parseKeyboardContent(parser, false);
                     break;
                 } else {
-                    throw new IllegalStartTag(parser, TAG_KEYBOARD);
+                    throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD);
                 }
             }
         }
@@ -393,7 +393,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
                 } else if (TAG_KEY_STYLE.equals(tag)) {
                     parseKeyStyle(parser, skip);
                 } else {
-                    throw new IllegalStartTag(parser, TAG_ROW);
+                    throw new XmlParseUtils.IllegalStartTag(parser, TAG_ROW);
                 }
             } else if (event == XmlPullParser.END_TAG) {
                 final String tag = parser.getName();
@@ -407,20 +407,20 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
                 } else if (TAG_KEY_STYLE.equals(tag)) {
                     continue;
                 } else {
-                    throw new IllegalEndTag(parser, TAG_ROW);
+                    throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW);
                 }
             }
         }
     }
 
-    private Row parseRowAttributes(XmlPullParser parser) {
+    private Row parseRowAttributes(XmlPullParser parser) throws XmlPullParserException {
         final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
                 R.styleable.Keyboard);
         try {
             if (a.hasValue(R.styleable.Keyboard_horizontalGap))
-                throw new IllegalAttribute(parser, "horizontalGap");
+                throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap");
             if (a.hasValue(R.styleable.Keyboard_verticalGap))
-                throw new IllegalAttribute(parser, "verticalGap");
+                throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap");
             return new Row(mResources, mParams, parser, mCurrentY);
         } finally {
             a.recycle();
@@ -444,7 +444,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
                 } else if (TAG_KEY_STYLE.equals(tag)) {
                     parseKeyStyle(parser, skip);
                 } else {
-                    throw new IllegalStartTag(parser, TAG_KEY);
+                    throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY);
                 }
             } else if (event == XmlPullParser.END_TAG) {
                 final String tag = parser.getName();
@@ -460,7 +460,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
                 } else if (TAG_KEY_STYLE.equals(tag)) {
                     continue;
                 } else {
-                    throw new IllegalEndTag(parser, TAG_KEY);
+                    throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
                 }
             }
         }
@@ -469,13 +469,13 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
     private void parseKey(XmlPullParser parser, Row row, boolean skip)
             throws XmlPullParserException, IOException {
         if (skip) {
-            checkEndTag(TAG_KEY, parser);
+            XmlParseUtils.checkEndTag(TAG_KEY, parser);
         } else {
             final Key key = new Key(mResources, mParams, row, parser, mKeyStyles);
             if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d moreKeys=%s />",
                     TAG_KEY, (key.isEnabled() ? "" : " disabled"), key.mLabel, key.mCode,
                     Arrays.toString(key.mMoreKeys)));
-            checkEndTag(TAG_KEY, parser);
+            XmlParseUtils.checkEndTag(TAG_KEY, parser);
             endKey(key);
         }
     }
@@ -483,11 +483,11 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
     private void parseSpacer(XmlPullParser parser, Row row, boolean skip)
             throws XmlPullParserException, IOException {
         if (skip) {
-            checkEndTag(TAG_SPACER, parser);
+            XmlParseUtils.checkEndTag(TAG_SPACER, parser);
         } else {
             final Key.Spacer spacer = new Key.Spacer(mResources, mParams, row, parser, mKeyStyles);
             if (DEBUG) Log.d(TAG, String.format("<%s />", TAG_SPACER));
-            checkEndTag(TAG_SPACER, parser);
+            XmlParseUtils.checkEndTag(TAG_SPACER, parser);
             endKey(spacer);
         }
     }
@@ -505,17 +505,21 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
     private void parseIncludeInternal(XmlPullParser parser, Row row, boolean skip)
             throws XmlPullParserException, IOException {
         if (skip) {
-            checkEndTag(TAG_INCLUDE, parser);
+            XmlParseUtils.checkEndTag(TAG_INCLUDE, parser);
         } else {
             final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
                     R.styleable.Keyboard_Include);
-            final int keyboardLayout = a.getResourceId(
-                    R.styleable.Keyboard_Include_keyboardLayout, 0);
-            a.recycle();
+            int keyboardLayout = 0;
+            try {
+                XmlParseUtils.checkAttributeExists(a,
+                        R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout",
+                        TAG_INCLUDE, parser);
+                keyboardLayout = a.getResourceId(R.styleable.Keyboard_Include_keyboardLayout, 0);
+            } finally {
+                a.recycle();
+            }
 
-            checkEndTag(TAG_INCLUDE, parser);
-            if (keyboardLayout == 0)
-                throw new ParseException("No keyboardLayout attribute in <include/>", parser);
+            XmlParseUtils.checkEndTag(TAG_INCLUDE, parser);
             if (DEBUG) Log.d(TAG, String.format("<%s keyboardLayout=%s />",
                     TAG_INCLUDE, mResources.getResourceEntryName(keyboardLayout)));
             final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout);
@@ -541,7 +545,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
                     }
                     break;
                 } else {
-                    throw new ParseException(
+                    throw new XmlParseUtils.ParseException(
                             "Included keyboard layout must have <merge> root element", parser);
                 }
             }
@@ -571,7 +575,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
                 } else if (TAG_DEFAULT.equals(tag)) {
                     selected |= parseDefault(parser, row, selected ? true : skip);
                 } else {
-                    throw new IllegalStartTag(parser, TAG_KEY);
+                    throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY);
                 }
             } else if (event == XmlPullParser.END_TAG) {
                 final String tag = parser.getName();
@@ -579,7 +583,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
                     if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_SWITCH));
                     break;
                 } else {
-                    throw new IllegalEndTag(parser, TAG_KEY);
+                    throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
                 }
             }
         }
@@ -716,14 +720,15 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
         return true;
     }
 
-    private void parseKeyStyle(XmlPullParser parser, boolean skip) {
+    private void parseKeyStyle(XmlPullParser parser, boolean skip)
+            throws XmlPullParserException {
         TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
                 R.styleable.Keyboard_KeyStyle);
         TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser),
                 R.styleable.Keyboard_Key);
         try {
             if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName))
-                throw new ParseException("<" + TAG_KEY_STYLE
+                throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE
                         + "/> needs styleName attribute", parser);
             if (!skip)
                 mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser);
@@ -733,13 +738,6 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
         }
     }
 
-    public static void checkEndTag(String tag, XmlPullParser parser)
-            throws XmlPullParserException, IOException {
-        if (parser.next() == XmlPullParser.END_TAG && tag.equals(parser.getName()))
-            return;
-        throw new NonEmptyTag(tag, parser);
-    }
-
     private void startKeyboard() {
         mCurrentY += mParams.mTopPadding;
         mTopEdge = true;
@@ -778,6 +776,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
     }
 
     private void endKeyboard() {
+        // nothing to do here.
     }
 
     private void addEdgeSpace(float width, Row row) {
@@ -824,41 +823,6 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
         return v.type == TypedValue.TYPE_STRING;
     }
 
-    @SuppressWarnings("serial")
-    public static class ParseException extends InflateException {
-        public ParseException(String msg, XmlPullParser parser) {
-            super(msg + " at line " + parser.getLineNumber());
-        }
-    }
-
-    @SuppressWarnings("serial")
-    public static class IllegalStartTag extends ParseException {
-        public IllegalStartTag(XmlPullParser parser, String parent) {
-            super("Illegal start tag " + parser.getName() + " in " + parent, parser);
-        }
-    }
-
-    @SuppressWarnings("serial")
-    public static class IllegalEndTag extends ParseException {
-        public IllegalEndTag(XmlPullParser parser, String parent) {
-            super("Illegal end tag " + parser.getName() + " in " + parent, parser);
-        }
-    }
-
-    @SuppressWarnings("serial")
-    private static class IllegalAttribute extends ParseException {
-        public IllegalAttribute(XmlPullParser parser, String attribute) {
-            super("Tag " + parser.getName() + " has illegal attribute " + attribute, parser);
-        }
-    }
-
-    @SuppressWarnings("serial")
-    private static class NonEmptyTag extends ParseException {
-        public NonEmptyTag(String tag, XmlPullParser parser) {
-            super(tag + " must be empty tag", parser);
-        }
-    }
-
     private static String textAttr(String value, String name) {
         return value != null ? String.format(" %s=%s", name, value) : "";
     }
diff --git a/java/src/com/android/inputmethod/keyboard/internal/XmlParseUtils.java b/java/src/com/android/inputmethod/keyboard/internal/XmlParseUtils.java
new file mode 100644
index 000000000..170be347b
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/XmlParseUtils.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.content.res.TypedArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+public class XmlParseUtils {
+    @SuppressWarnings("serial")
+    public static class ParseException extends XmlPullParserException {
+        public ParseException(String msg, XmlPullParser parser) {
+            super(msg + " at line " + parser.getLineNumber()
+                    + ", column " + parser.getColumnNumber());
+        }
+    }
+
+    @SuppressWarnings("serial")
+    public static class IllegalStartTag extends ParseException {
+        public IllegalStartTag(XmlPullParser parser, String parent) {
+            super("Illegal start tag " + parser.getName() + " in " + parent, parser);
+        }
+    }
+
+    @SuppressWarnings("serial")
+    public static class IllegalEndTag extends ParseException {
+        public IllegalEndTag(XmlPullParser parser, String parent) {
+            super("Illegal end tag " + parser.getName() + " in " + parent, parser);
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static class IllegalAttribute extends ParseException {
+        public IllegalAttribute(XmlPullParser parser, String attribute) {
+            super("Tag " + parser.getName() + " has illegal attribute " + attribute, parser);
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static class NonEmptyTag extends ParseException{
+        public NonEmptyTag(String tag, XmlPullParser parser) {
+            super(tag + " must be empty tag", parser);
+        }
+    }
+
+    public static void checkEndTag(String tag, XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        if (parser.next() == XmlPullParser.END_TAG && tag.equals(parser.getName()))
+            return;
+        throw new NonEmptyTag(tag, parser);
+    }
+
+    public static void checkAttributeExists(TypedArray attr, int attrId, String attrName,
+            String tag, XmlPullParser parser) throws XmlPullParserException {
+        if (attr.hasValue(attrId))
+            return;
+        throw new ParseException(
+                "No " + attrName + " attribute found in <" + tag + "/>", parser);
+    }
+}