aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2016-03-07 14:14:29 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2016-03-08 03:44:29 +0000
commit3a55f01cc98068d0133349ddb5c0043b74555565 (patch)
tree2e9fa5753d66d5098922ced4baa9612820e7260d /src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java
parenta9b7f4e1bd474afd005ad6943ce84bc8ef61eb97 (diff)
Part 2 of 5: Optimize the resource merge process, XmlProcessing.
Introduces the XmlDataResource and all the associated cruft that comes with parsing Android Resource value xmls: XmlValues, XmlValue. -- MOS_MIGRATED_REVID=116540181
Diffstat (limited to 'src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java')
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java b/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java
new file mode 100644
index 0000000000..1ed6631d1c
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java
@@ -0,0 +1,216 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// 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.google.devtools.build.android;
+
+import com.google.devtools.build.android.xml.AttrXmlResourceValue;
+import com.google.devtools.build.android.xml.IdXmlResourceValue;
+import com.google.devtools.build.android.xml.PluralXmlResourceValue;
+import com.google.devtools.build.android.xml.SimpleXmlResourceValue;
+import com.google.devtools.build.android.xml.StyleXmlResourceValue;
+import com.google.devtools.build.android.xml.StyleableXmlResourceValue;
+
+import com.android.resources.ResourceType;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+/**
+ * XmlValues provides methods for getting XmlValue derived classes.
+ *
+ * <p>Acts a static factory class containing the general xml parsing logic for resources
+ * that are declared inside the &lt;resources&gt; tag.
+ */
+public class XmlResourceValues {
+
+ private static final QName TAG_PLURALS = QName.valueOf("plurals");
+ private static final QName ATTR_QUANTITY = QName.valueOf("quantity");
+ private static final QName TAG_ATTR = QName.valueOf("attr");
+ private static final QName TAG_DECLARE_STYLEABLE = QName.valueOf("declare-styleable");
+ private static final QName TAG_ITEM = QName.valueOf("item");
+ private static final QName TAG_STYLE = QName.valueOf("style");
+ private static final QName TAG_RESOURCES = QName.valueOf("resources");
+ private static final QName ATTR_FORMAT = QName.valueOf("format");
+ private static final QName ATTR_NAME = QName.valueOf("name");
+ private static final QName ATTR_VALUE = QName.valueOf("value");
+ private static final QName ATTR_PARENT = QName.valueOf("parent");
+ private static final QName ATTR_TYPE = QName.valueOf("type");
+
+ static XmlResourceValue parsePlurals(XMLEventReader eventReader) throws XMLStreamException {
+ Map<String, String> values = new HashMap<>();
+ for (XMLEvent element = eventReader.nextTag();
+ !isEndTag(element, TAG_PLURALS);
+ element = eventReader.nextTag()) {
+ if (isItem(element)) {
+ values.put(
+ getElementAttributeByName(element.asStartElement(), ATTR_QUANTITY),
+ eventReader.getElementText());
+ }
+ }
+ return PluralXmlResourceValue.of(values);
+ }
+
+ static XmlResourceValue parseStyle(XMLEventReader eventReader, StartElement start)
+ throws XMLStreamException {
+ Map<String, String> values = new HashMap<>();
+ for (XMLEvent element = eventReader.nextTag();
+ !isEndTag(element, TAG_STYLE);
+ element = eventReader.nextTag()) {
+ if (isItem(element)) {
+ values.put(getElementName(element.asStartElement()), eventReader.getElementText());
+ }
+ }
+ return StyleXmlResourceValue.of(parseReferenceFromElementAttribute(start, ATTR_PARENT), values);
+ }
+
+ static void parseDeclareStyleable(
+ FullyQualifiedName.Factory fqnFactory,
+ Path path,
+ List<DataResource> nonOverwritable,
+ List<DataResource> overwritable,
+ XMLEventReader eventReader,
+ StartElement start)
+ throws XMLStreamException {
+ String styleableName = getElementName(start);
+ List<String> members = new ArrayList<>();
+ for (XMLEvent element = eventReader.nextTag();
+ !isEndTag(element, TAG_DECLARE_STYLEABLE);
+ element = eventReader.nextTag()) {
+ if (isStartTag(element, TAG_ATTR)) {
+ StartElement attr = element.asStartElement();
+ members.add(getElementName(attr));
+ String attrName = getElementName(attr);
+ overwritable.add(
+ XmlDataResource.of(
+ fqnFactory.create(ResourceType.ATTR, attrName),
+ path,
+ parseAttr(eventReader, start)));
+ }
+ }
+ nonOverwritable.add(
+ XmlDataResource.of(
+ fqnFactory.create(ResourceType.STYLEABLE, styleableName),
+ path,
+ StyleableXmlResourceValue.of(members)));
+ }
+
+ static XmlResourceValue parseAttr(XMLEventReader eventReader, StartElement start)
+ throws XMLStreamException {
+ return AttrXmlResourceValue.from(
+ start, getElementAttributeByName(start, ATTR_FORMAT), eventReader);
+ }
+
+ static XmlResourceValue parseId() {
+ return IdXmlResourceValue.of();
+ }
+
+ static XmlResourceValue parseSimple(XMLEventReader eventReader, ResourceType resourceType)
+ throws XMLStreamException {
+ return SimpleXmlResourceValue.of(
+ SimpleXmlResourceValue.Type.from(resourceType), eventReader.getElementText());
+ }
+
+ /* XML helper methods follow. */
+ // TODO(corysmith): Move these to a wrapper class for XMLEventReader.
+ private static String parseReferenceFromElementAttribute(StartElement element, QName name)
+ throws XMLStreamException {
+ String value = getElementAttributeByName(element, name);
+ if (value.startsWith("?") || value.startsWith("@")) {
+ return value.substring(1);
+ }
+ throw new XMLStreamException(
+ String.format("Invalid resource reference from %s in %s", name, element),
+ element.getLocation());
+ }
+
+ public static String getElementAttributeByName(StartElement element, QName name) {
+ Attribute attribute = element.getAttributeByName(name);
+ return attribute == null ? null : attribute.getValue();
+ }
+
+ public static String getElementValue(StartElement start) {
+ return getElementAttributeByName(start, ATTR_VALUE);
+ }
+
+ public static String getElementName(StartElement start) {
+ return getElementAttributeByName(start, ATTR_NAME);
+ }
+
+ public static String getElementType(StartElement start) {
+ return getElementAttributeByName(start, ATTR_TYPE);
+ }
+
+ public static boolean isTag(XMLEvent event, QName subTagType) {
+ if (event.isStartElement()) {
+ return isStartTag(event, subTagType);
+ }
+ if (event.isEndElement()) {
+ return isEndTag(event, subTagType);
+ }
+ return false;
+ }
+
+ public static boolean isItem(XMLEvent start) {
+ return isTag(start, TAG_ITEM);
+ }
+
+ public static boolean isEndTag(XMLEvent event, QName subTagType) {
+ if (event.isEndElement()) {
+ return subTagType.equals(event.asEndElement().getName());
+ }
+ return false;
+ }
+
+ public static boolean isStartTag(XMLEvent event, QName subTagType) {
+ if (event.isStartElement()) {
+ return subTagType.equals(event.asStartElement().getName());
+ }
+ return false;
+ }
+
+ public static XMLEvent peekNextTag(XMLEventReader eventReader) throws XMLStreamException {
+ while (!(eventReader.peek().isEndElement() || eventReader.peek().isStartElement())) {
+ eventReader.nextEvent();
+ }
+ return eventReader.peek();
+ }
+
+ static StartElement findNextStart(XMLEventReader eventReader) throws XMLStreamException {
+ while (eventReader.hasNext()) {
+ XMLEvent event = eventReader.nextEvent();
+ if (event.isStartElement()) {
+ return event.asStartElement();
+ }
+ }
+ return null;
+ }
+
+ static boolean moveToResources(XMLEventReader eventReader) throws XMLStreamException {
+ while (eventReader.hasNext()) {
+ if (findNextStart(eventReader).getName().equals(TAG_RESOURCES)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}