package de.luhmer.owncloudnewsreader.helper; import android.content.Context; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.StringWriter; import java.util.HashMap; import java.util.List; import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; import de.luhmer.owncloudnewsreader.database.model.Feed; import de.luhmer.owncloudnewsreader.database.model.Folder; /** * Created by David on 14.01.2016. */ public class OpmlXmlParser { //Create XML public static String GenerateOPML(Context context) { XmlSerializer serializer = Xml.newSerializer(); StringWriter writer = new StringWriter(); try { serializer.setOutput(writer); serializer.startDocument("UTF-8", true); serializer.startTag("", "opml"); serializer.attribute("", "version", "2.0"); serializer.startTag("", "head"); serializer.startTag("", "title"); serializer.text("Subscriptions"); serializer.endTag("", "title"); serializer.endTag("", "head"); serializer.startTag("", "body"); DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(context); List<Folder> folderList = dbConn.getListOfFolders(); List<Feed> feedList = dbConn.getListOfFeeds(); //Process all feeds in folders for(Folder folder : folderList) { serializer.startTag("", "outline"); serializer.attribute("", "title", folder.getLabel()); serializer.attribute("", "text", folder.getLabel()); for(Feed feed : folder.getFeedList()) { feedList.remove(feed);//Remove feed from feedlist (So only feeds without folders will remain) GenerateXMLForFeed(serializer, feed); } serializer.endTag("", "outline"); } //All feeds without folder for(Feed feed : feedList) { GenerateXMLForFeed(serializer, feed); } serializer.endTag("", "body"); serializer.endTag("", "opml"); serializer.endDocument(); return writer.toString(); } catch (Exception e) { throw new RuntimeException(e); } } private static void GenerateXMLForFeed(XmlSerializer serializer, Feed feed) throws IOException { serializer.startTag("", "outline"); serializer.attribute("", "title", feed.getFeedTitle()); serializer.attribute("", "text", feed.getFeedTitle()); serializer.attribute("", "type", "rss"); serializer.attribute("", "xmlUrl", feed.getLink()); //serializer.attribute("", "htmlUrl", key); serializer.endTag("", "outline"); } //Parse XML // We don't use namespaces private static final String ns = null; public static HashMap<String, String> ReadFeed(XmlPullParser parser) throws XmlPullParserException, IOException { HashMap<String, String> extractedUrls = new HashMap<>(); parser.require(XmlPullParser.START_TAG, ns, "opml"); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) { continue; } String name = parser.getName(); // Starts by looking for the entry tag if (name.equals("body")) { extractedUrls.putAll(readFolder(parser)); } else { Skip(parser); } } return extractedUrls; } private static class Entry { public Entry(String folderName, String feedUrl) { this.feedUrl = feedUrl; this.folderName = folderName; } public String folderName; public String feedUrl; } private static HashMap<String, String> readFolder(XmlPullParser parser) throws XmlPullParserException, IOException { HashMap<String, String> extractedUrls = new HashMap<>(); String name; String folderName = null; parser.require(XmlPullParser.START_TAG, ns, "body"); while(parser.next() >= 0) { //Loop over all if(parser.getEventType() == XmlPullParser.END_TAG) { //If read endtag and folder Name is != null if(folderName == null) { //If end tag is read and we aren't exiting a folder --> exit! break; } folderName = null; } if (parser.getEventType() != XmlPullParser.START_TAG) { continue; } name = parser.getName(); if (name.equals("outline")) { Entry entry = ReadOutline(parser); if (entry.folderName != null) { folderName = entry.folderName; } else { entry.folderName = folderName; extractedUrls.put(entry.feedUrl, entry.folderName); parser.next(); //Read closing tag } } } return extractedUrls; } // Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them off // to their respective "read" methods for processing. Otherwise, skips the tag. private static Entry ReadOutline(XmlPullParser parser) throws XmlPullParserException, IOException { //parser.require(XmlPullParser.START_TAG, ns, "outline"); String link = parser.getAttributeValue(null, "xmlUrl"); String title = null; if(link == null) { //Parse folder title if no feedUrl is available title = parser.getAttributeValue(null, "title"); } return new Entry(title, link); } private static void Skip(XmlPullParser parser) throws XmlPullParserException, IOException { if (parser.getEventType() != XmlPullParser.START_TAG) { throw new IllegalStateException(); } int depth = 1; while (depth != 0) { switch (parser.next()) { case XmlPullParser.END_TAG: depth--; break; case XmlPullParser.START_TAG: depth++; break; } } } }