/*
* This file is part of connotea-java.
*
* connotea-java 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 3 of the License, or
* (at your option) any later version.
*
* connotea-java 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, see <http://www.gnu.org/licenses/>.
*/
package org.connotea;
import static org.connotea.StringUtils.toAuthor;
import static org.connotea.StringUtils.toDate;
import static org.connotea.StringUtils.toLong;
import java.util.ArrayList;
import java.util.List;
import org.restlet.data.Reference;
import org.restlet.resource.DomRepresentation;
import org.restlet.resource.Representation;
import org.restlet.util.NodeSet;
import org.w3c.dom.Node;
/**
* Parses instances of {@link Bookmark} from XML
* {@link org.restlet.resource.Representation}s of the same returned as part of
* calls to the Connotea API.
*
* @author <a href="mailto:christopher.townson@googlemail.com">Christopher
* Townson</a>
*/
public class BookmarkParser {
/**
* Parse the provided {@link org.restlet.resource.Representation} as a list
* of zero or more {@link Bookmark}s.
*
* @param representation the {@link org.restlet.resource.Representation} of
* a list of zero or more {@link Bookmark}(s)
* @return the {@link Bookmark}(s)
* @throws ParseException if the {@link org.restlet.resource.Representation}
* could not be parsed as a list of one or more {@link Bookmark}
* (s)
* @see #isValid(Representation)
*/
public List<Bookmark> parse(Representation representation)
throws ParseException {
List<Bookmark> bookmarks = new ArrayList<Bookmark>();
if (!isValid(representation)) {
throw new ParseException("invalid representation: "
+ representation);
}
try {
NodeSet nodes = new DomRepresentation(representation)
.getNodes("/RDF/URI");
for (Node node : nodes) {
bookmarks.add(getBookmark(node));
}
} catch (Exception e) {
throw new ParseException(e);
}
return bookmarks;
}
/**
* Determine if the provided {@link org.restlet.resource.Representation} is
* valid (i.e. can be parsed by this parser).
*
* @param representation the {@link org.restlet.resource.Representation} to
* test for parseability
* @return <code>true</code> if the
* {@link org.restlet.resource.Representation} is parseable as a
* list of zero or more {@link Bookmark}(s)
*/
public boolean isValid(Representation representation) {
return (representation != null)
&& (new DomRepresentation(representation).getNodes("/RDF/URI") != null);
}
private Bookmark getBookmark(Node node) {
Bookmark bookmark = new Bookmark();
List<String> postedBy = new ArrayList<String>();
List<Tag> tags = new ArrayList<Tag>();
Node firstChild = node.getFirstChild();
while (firstChild.getNextSibling() != null) {
String name = firstChild.getNodeName();
String text = firstChild.getTextContent();
if ("link".equals(name)) {
bookmark.setLink(new Reference(text));
}
if ("dc:title".equals(name)) {
bookmark.setTitle(text);
}
if ("tag".equals(name)) {
tags.add(new Tag(text));
}
if ("postedBy".equals(name)) {
postedBy.add(text);
}
if ("postCount".equals(name)) {
bookmark.setPostCount(toLong(text));
}
if ("hash".equals(name)) {
bookmark.setHash(text);
}
if ("bookmarkID".equals(name)) {
bookmark.setBookmarkID(toLong(text));
}
if ("created".equals(name)) {
bookmark.setCreated(toDate(text));
}
if ("updated".equals(name)) {
bookmark.setUpdated(toDate(text));
}
if ("firstUser".equals(name)) {
bookmark.setFirstUser(text);
}
if ("citation".equals(name)) {
bookmark.setCitation(getCitation(firstChild));
}
firstChild = firstChild.getNextSibling();
}
bookmark.setPostedBy(postedBy);
bookmark.setTags(tags);
return bookmark;
}
private Citation getCitation(Node node) {
Citation citation = new Citation();
List<Author> authors = new ArrayList<Author>();
Node firstChild = node.getFirstChild();
while (firstChild.getNextSibling() != null) {
if ("rdf:Description".equals(firstChild.getNodeName())) {
Node secondChild = firstChild.getFirstChild();
while (secondChild.getNextSibling() != null) {
String name = secondChild.getNodeName();
String text = secondChild.getTextContent();
if ("citationID".equals(name)) {
citation.setCitationId(toLong(text));
}
if ("prism:title".equals(name)) {
citation.setTitle(text);
}
if ("foaf:maker".equals(name)) {
authors.add(toAuthor(text));
}
if ("dc:date".equals(name)) {
citation.setDate(toDate(text));
}
if ("journalID".equals(name)) {
citation.setJournalId(toLong(text));
}
if ("prism:publicationName".equals(name)) {
citation.setPublicationName(text);
}
if ("prism:issn".equals(name)) {
citation.setIssn(text);
}
if ("prism:volume".equals(name)) {
citation.setVolume(text);
}
if ("prism:number".equals(name)) {
citation.setNumber(text);
}
if ("prism:startingPage".equals(name)) {
citation.setStartingPage(text);
}
if ("prism:endingPage".equals(name)) {
citation.setEndingPage(text);
}
if ("doiResolver".equals(name)) {
if (secondChild.getAttributes().getLength() > 0) {
citation.setDoiResolver(new Reference(secondChild
.getAttributes().item(0).getTextContent()));
}
}
if ("pmidResolver".equals(name)) {
if (secondChild.getAttributes().getLength() > 0) {
citation.setPmidResolver(new Reference(secondChild
.getAttributes().item(0).getTextContent()));
}
}
if ("dc:identifier".equals(name)) {
getIdentifier(secondChild, citation);
}
secondChild = secondChild.getNextSibling();
}
}
firstChild = firstChild.getNextSibling();
}
citation.setAuthors(authors);
return citation;
}
private void getIdentifier(Node node, Citation citation) {
Node clone = node.cloneNode(true);
while (node.getPreviousSibling() != null) {
if (node.getPreviousSibling().getNodeType() == Node.ELEMENT_NODE) {
String name = node.getPreviousSibling().getNodeName();
if ("doiResolver".equals(name)) {
citation.setDoi(clone.getTextContent());
break;
} else if ("pmidResolver".equals(name)) {
citation.setPmid(clone.getTextContent());
break;
}
}
node = node.getPreviousSibling();
}
}
}