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)));
 }