public static void parse( XMLInputFactory xmlInputFactory, Path source, FullyQualifiedName fileKey, FullyQualifiedName.Factory fqnFactory, KeyValueConsumer<DataKey, DataResource> overwritingConsumer, KeyValueConsumer<DataKey, DataResource> combiningConsumer) throws IOException, XMLStreamException { ImmutableSet.Builder<String> newIds = ImmutableSet.builder(); try (BufferedInputStream inStream = new BufferedInputStream(Files.newInputStream(source))) { XMLEventReader eventReader = xmlInputFactory.createXMLEventReader(inStream, StandardCharsets.UTF_8.toString()); // Go through every start tag and look at the values of all attributes (the attribute does // not need to be android:id, e.g., android:layout_above="@+id/UpcomingView"). // If the any attribute's value begins with @+id/, then track it, since aapt seems to be // forgiving and allow even non-android namespaced attributes to define a new ID. while (eventReader.hasNext()) { XMLEvent event = eventReader.nextEvent(); if (event.isStartElement()) { StartElement start = event.asStartElement(); Iterator<Attribute> attributes = XmlResourceValues.iterateAttributesFrom(start); while (attributes.hasNext()) { Attribute attribute = attributes.next(); String value = attribute.getValue(); if (value.startsWith(SdkConstants.NEW_ID_PREFIX)) { String idName = value.substring(SdkConstants.NEW_ID_PREFIX.length()); newIds.add(idName); } } } } eventReader.close(); } ImmutableSet<String> idResources = newIds.build(); overwritingConsumer.consume(fileKey, DataValueFile.of(source)); for (String id : idResources) { combiningConsumer.consume( fqnFactory.create(ResourceType.ID, id), DataResourceXml.createWithNoNamespace(source, IdXmlResourceValue.of())); } }
static void parseDeclareStyleable( FullyQualifiedName.Factory fqnFactory, Path path, KeyValueConsumer<DataKey, DataResource> overwritingConsumer, KeyValueConsumer<DataKey, DataResource> nonOverwritingConsumer, XMLEventReader eventReader, StartElement start) throws XMLStreamException { 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)); overwritingConsumer.consume( fqnFactory.create(ResourceType.ATTR, getElementName(attr)), DataResourceXml.of(path, parseAttr(eventReader, start))); } } nonOverwritingConsumer.consume( fqnFactory.create(ResourceType.STYLEABLE, getElementName(start)), DataResourceXml.of(path, StyleableXmlResourceValue.of(members))); }