/* * Copyright (C) 2010-2011 Geometer Plus <contact@geometerplus.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ package org.geometerplus.fbreader.network.opds; import org.geometerplus.zlibrary.core.constants.XMLNamespaces; import org.geometerplus.zlibrary.core.xml.*; import org.geometerplus.fbreader.network.atom.*; public class OPDSXMLReader extends ATOMXMLReader<OPDSFeedMetadata, OPDSEntry> { public static final String KEY_PRICE = "price"; private DCDate myDCIssued; private String myPriceCurrency; public OPDSXMLReader(ATOMFeedHandler<OPDSFeedMetadata,OPDSEntry> handler, boolean readEntryNotFeed) { super(handler, readEntryNotFeed); } protected final OPDSFeedMetadata getOPDSFeed() { return getATOMFeed(); } protected final OPDSEntry getOPDSEntry() { return getATOMEntry(); } protected final OPDSLink getOPDSLink() { return (OPDSLink)getATOMLink(); } private static final int FE_DC_LANGUAGE = ATOM_STATE_FIRST_UNUSED; private static final int FE_DC_ISSUED = ATOM_STATE_FIRST_UNUSED + 1; private static final int FE_DC_PUBLISHER = ATOM_STATE_FIRST_UNUSED + 2; private static final int FE_CALIBRE_SERIES = ATOM_STATE_FIRST_UNUSED + 3; private static final int FE_CALIBRE_SERIES_INDEX = ATOM_STATE_FIRST_UNUSED + 4; private static final int FEL_PRICE = ATOM_STATE_FIRST_UNUSED + 5; private static final int FEL_FORMAT = ATOM_STATE_FIRST_UNUSED + 6; private static final int OPENSEARCH_TOTALRESULTS = ATOM_STATE_FIRST_UNUSED + 7; private static final int OPENSEARCH_ITEMSPERPAGE = ATOM_STATE_FIRST_UNUSED + 8; private static final int OPENSEARCH_STARTINDEX = ATOM_STATE_FIRST_UNUSED + 9; private static final int FEC_HACK_SPAN = ATOM_STATE_FIRST_UNUSED + 10; private static final int FBREADER_VIEW = ATOM_STATE_FIRST_UNUSED + 11; private static final String TAG_PRICE = "price"; private static final String TAG_HACK_SPAN = "span"; private static final String DC_TAG_LANGUAGE = "language"; private static final String DC_TAG_ISSUED = "issued"; private static final String DC_TAG_PUBLISHER = "publisher"; private static final String DC_TAG_FORMAT = "format"; private static final String CALIBRE_TAG_SERIES = "series"; private static final String CALIBRE_TAG_SERIES_INDEX = "series_index"; private static final String OPENSEARCH_TAG_TOTALRESULTS = "totalResults"; private static final String OPENSEARCH_TAG_ITEMSPERPAGE = "itemsPerPage"; private static final String OPENSEARCH_TAG_STARTINDEX = "startIndex"; private static final String FBREADER_TAG_VIEW = "view"; @Override protected OPDSFeedMetadata createFeed(ZLStringMap attributes) { return new OPDSFeedMetadata(attributes); } @Override protected OPDSLink createLink(ZLStringMap attributes) { return new OPDSLink(attributes); } @Override protected OPDSEntry createEntry(ZLStringMap attributes) { return new OPDSEntry(attributes); } @Override public boolean startElementHandler(String ns, String tag, ZLStringMap attributes, String bufferContent) { switch (myState) { case FEED: if (ns == XMLNamespaces.OpenSearch) { if (tag == OPENSEARCH_TAG_TOTALRESULTS) { myState = OPENSEARCH_TOTALRESULTS; } else if (tag == OPENSEARCH_TAG_ITEMSPERPAGE) { myState = OPENSEARCH_ITEMSPERPAGE; } else if (tag == OPENSEARCH_TAG_STARTINDEX) { myState = OPENSEARCH_STARTINDEX; } return false; } else if (ns == XMLNamespaces.FBReaderCatalogMetadata){ if (tag == FBREADER_TAG_VIEW) { myState = FBREADER_VIEW; } } else { return super.startElementHandler(ns, tag, attributes, bufferContent); } case F_ENTRY: if (ns == XMLNamespaces.DublinCoreTerms) { if (tag == DC_TAG_LANGUAGE) { myState = FE_DC_LANGUAGE; } else if (tag == DC_TAG_ISSUED) { myDCIssued = new DCDate(attributes); myState = FE_DC_ISSUED; } else if (tag == DC_TAG_PUBLISHER) { myState = FE_DC_PUBLISHER; } return false; } else if (ns == XMLNamespaces.CalibreMetadata) { if (tag == CALIBRE_TAG_SERIES) { myState = FE_CALIBRE_SERIES; } else if (tag == CALIBRE_TAG_SERIES_INDEX) { myState = FE_CALIBRE_SERIES_INDEX; } return false; } else { return super.startElementHandler(ns, tag, attributes, bufferContent); } case FE_LINK: if (ns == XMLNamespaces.Opds && tag == TAG_PRICE) { myPriceCurrency = attributes.getValue("currencycode"); myState = FEL_PRICE; return false; } if (ns == XMLNamespaces.DublinCoreTerms && tag == DC_TAG_FORMAT) { myState = FEL_FORMAT; return false; } else { return super.startElementHandler(ns, tag, attributes, bufferContent); } case FE_CONTENT: super.startElementHandler(ns, tag, attributes, bufferContent); // FIXME: HACK: html handling must be implemeted neatly if (tag == TAG_HACK_SPAN || attributes.getValue("class") == "price") { myState = FEC_HACK_SPAN; } return false; default: return super.startElementHandler(ns, tag, attributes, bufferContent); } } @Override public boolean endElementHandler(String ns, String tag, String bufferContent) { switch (myState) { default: return super.endElementHandler(ns, tag, bufferContent); case FEL_PRICE: if (ns == XMLNamespaces.Opds && tag == TAG_PRICE) { if (bufferContent != null && myPriceCurrency != null) { getOPDSLink().Prices.add(new OPDSPrice(bufferContent.intern(), myPriceCurrency)); myPriceCurrency = null; } myState = FE_LINK; } return false; case FEL_FORMAT: if (ns == XMLNamespaces.DublinCoreTerms && tag == DC_TAG_FORMAT) { if (bufferContent != null) { getOPDSLink().Formats.add(bufferContent.intern()); } myState = FE_LINK; } return false; case FEC_HACK_SPAN: // FIXME: HACK myFormattedBuffer.appendText(bufferContent); myFormattedBuffer.appendEndTag(tag); myFormattedBuffer.appendText("<br/>"); if (bufferContent != null) { getOPDSEntry().addAttribute(KEY_PRICE, bufferContent.intern()); } myState = FE_CONTENT; return false; case FE_DC_LANGUAGE: if (ns == XMLNamespaces.DublinCoreTerms && tag == DC_TAG_LANGUAGE) { // FIXME:language can be lost:buffer will be truncated, if there are extension tags inside the <dc:language> tag getOPDSEntry().DCLanguage = bufferContent; myState = F_ENTRY; } return false; case FE_DC_ISSUED: if (ns == XMLNamespaces.DublinCoreTerms && tag == DC_TAG_ISSUED) { // FIXME:issued can be lost:buffer will be truncated, if there are extension tags inside the <dc:issued> tag if (ATOMDateConstruct.parse(bufferContent, myDCIssued)) { getOPDSEntry().DCIssued = myDCIssued; } myDCIssued = null; myState = F_ENTRY; } return false; case FE_DC_PUBLISHER: if (ns == XMLNamespaces.DublinCoreTerms && tag == DC_TAG_PUBLISHER) { // FIXME:publisher can be lost:buffer will be truncated, if there are extension tags inside the <dc:publisher> tag getOPDSEntry().DCPublisher = bufferContent; myState = F_ENTRY; } return false; case FE_CALIBRE_SERIES: if (ns == XMLNamespaces.CalibreMetadata && tag == CALIBRE_TAG_SERIES) { getOPDSEntry().SeriesTitle = bufferContent; myState = F_ENTRY; } return false; case FE_CALIBRE_SERIES_INDEX: if (ns == XMLNamespaces.CalibreMetadata && tag == CALIBRE_TAG_SERIES_INDEX) { if (bufferContent != null) { try { getOPDSEntry().SeriesIndex = Float.parseFloat(bufferContent); } catch (NumberFormatException ex) { } } myState = F_ENTRY; } return false; case OPENSEARCH_TOTALRESULTS: if (ns == XMLNamespaces.OpenSearch && tag == OPENSEARCH_TAG_TOTALRESULTS) { if (getOPDSFeed() != null && bufferContent != null) { try { getOPDSFeed().OpensearchTotalResults = Integer.parseInt(bufferContent); } catch (NumberFormatException ex) { } } myState = FEED; } return false; case OPENSEARCH_ITEMSPERPAGE: if (ns == XMLNamespaces.OpenSearch && tag == OPENSEARCH_TAG_ITEMSPERPAGE) { if (getOPDSFeed() != null && bufferContent != null) { try { getOPDSFeed().OpensearchItemsPerPage = Integer.parseInt(bufferContent); } catch (NumberFormatException ex) { } } myState = FEED; } return false; case OPENSEARCH_STARTINDEX: if (ns == XMLNamespaces.OpenSearch && tag == OPENSEARCH_TAG_STARTINDEX) { if (getOPDSFeed() != null && bufferContent != null) { try { getOPDSFeed().OpensearchStartIndex = Integer.parseInt(bufferContent); } catch (NumberFormatException ex) { } } myState = FEED; } return false; case FBREADER_VIEW: if (ns == XMLNamespaces.FBReaderCatalogMetadata && tag == FBREADER_TAG_VIEW) { if (getOPDSFeed() != null) { getOPDSFeed().ViewType = bufferContent; } myState = FEED; } return false; } } }