From 1bc1f6854815093a4255f58c6ddc900dc54c65f2 Mon Sep 17 00:00:00 2001 From: hudajkhan Date: Fri, 10 Feb 2017 10:49:28 -0500 Subject: [PATCH] [VIVO-1316] moving base lookup architecture for vocabulary services to Vitro (#55) --- .../mannlib/semservices/bo/BaseObject.java | 25 ++ .../mannlib/semservices/bo/Concept.java | 163 ++++++++ .../mannlib/semservices/bo/ConceptInfo.java | 32 ++ .../semservices/bo/SemanticServicesError.java | 75 ++++ .../bo/SemanticServicesInfoBase.java | 29 ++ .../exceptions/ConceptsNotFoundException.java | 15 + .../service/ExternalConceptService.java | 27 ++ .../util/MetadataNamespaceContext.java | 26 ++ .../mannlib/semservices/util/SKOSUtils.java | 266 +++++++++++++ .../mannlib/semservices/util/XMLUtils.java | 361 ++++++++++++++++++ 10 files changed, 1019 insertions(+) create mode 100644 api/src/main/java/edu/cornell/mannlib/semservices/bo/BaseObject.java create mode 100644 api/src/main/java/edu/cornell/mannlib/semservices/bo/Concept.java create mode 100644 api/src/main/java/edu/cornell/mannlib/semservices/bo/ConceptInfo.java create mode 100644 api/src/main/java/edu/cornell/mannlib/semservices/bo/SemanticServicesError.java create mode 100644 api/src/main/java/edu/cornell/mannlib/semservices/bo/SemanticServicesInfoBase.java create mode 100644 api/src/main/java/edu/cornell/mannlib/semservices/exceptions/ConceptsNotFoundException.java create mode 100644 api/src/main/java/edu/cornell/mannlib/semservices/service/ExternalConceptService.java create mode 100644 api/src/main/java/edu/cornell/mannlib/semservices/util/MetadataNamespaceContext.java create mode 100644 api/src/main/java/edu/cornell/mannlib/semservices/util/SKOSUtils.java create mode 100644 api/src/main/java/edu/cornell/mannlib/semservices/util/XMLUtils.java diff --git a/api/src/main/java/edu/cornell/mannlib/semservices/bo/BaseObject.java b/api/src/main/java/edu/cornell/mannlib/semservices/bo/BaseObject.java new file mode 100644 index 000000000..ce4d8aa66 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/semservices/bo/BaseObject.java @@ -0,0 +1,25 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.semservices.bo; + +public class BaseObject { + /** + * Simple JavaBean domain object with an id property. + * Used as a base class for objects needing this property. + */ + private Integer id; + + public void setId(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public boolean isNew() { + return (this.id == null); + } + + + +} diff --git a/api/src/main/java/edu/cornell/mannlib/semservices/bo/Concept.java b/api/src/main/java/edu/cornell/mannlib/semservices/bo/Concept.java new file mode 100644 index 000000000..434f82ea4 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/semservices/bo/Concept.java @@ -0,0 +1,163 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.semservices.bo; + +import java.util.ArrayList; +import java.util.List; + +public class Concept { + + private String definedBy; + private String conceptId; + private String bestMatch; + private String label; + private String type; + private String definition; + private String uri; + private String schemeURI; + private List broaderURIList; + private List narrowerURIList; + private List exactMatchURIList; + private List closeMatchURIList; + private List altLabelList; + + /** + * default constructor + */ + public Concept() { + this.broaderURIList = new ArrayList(); + this.narrowerURIList = new ArrayList(); + this.exactMatchURIList = new ArrayList(); + this.closeMatchURIList = new ArrayList(); + } + + /** + * @return the conceptId + */ + public String getConceptId() { + return conceptId; + } + /** + * @param conceptId the conceptId to set + */ + public void setConceptId(String conceptId) { + this.conceptId = conceptId; + } + /** + * @return the label + */ + public String getLabel() { + return label; + } + /** + * @param label the label to set + */ + public void setLabel(String label) { + this.label = label; + } + /** + * @return the type + */ + public String getType() { + return type; + } + /** + * @param type the type to set + */ + public void setType(String type) { + this.type = type; + } + /** + * @return the definition + */ + public String getDefinition() { + return definition; + } + /** + * @param definition the definition to set + */ + public void setDefinition(String definition) { + this.definition = definition; + } + /** + * @return the uri + */ + public String getUri() { + return uri; + } + /** + * @param uri the uri to set + */ + public void setUri(String uri) { + this.uri = uri; + } + /** + * @return the definedBy + */ + public String getDefinedBy() { + return definedBy; + } + /** + * @param definedBy the definedBy to set + */ + public void setDefinedBy(String definedBy) { + this.definedBy = definedBy; + } + /** + * @return the schemeURI + */ + public String getSchemeURI() { + return schemeURI; + } + /** + * @param schemeURI the schemeURI to set + */ + public void setSchemeURI(String schemeURI) { + this.schemeURI = schemeURI; + } + /** + * @return the bestMatch + */ + public String getBestMatch() { + return bestMatch; + } + /** + * @param bestMatch the bestMatch to set + */ + public void setBestMatch(String bestMatch) { + this.bestMatch = bestMatch; + } +public List getBroaderURIList() { + return broaderURIList; +} +public void setBroaderURIList(List broaderURIList) { + this.broaderURIList = broaderURIList; +} +public List getNarrowerURIList() { + return narrowerURIList; +} +public void setNarrowerURIList(List narrowerURIList) { + this.narrowerURIList = narrowerURIList; +} +public List getExactMatchURIList() { + return exactMatchURIList; +} +public void setExactMatchURIList(List exactMatchURIList) { + this.exactMatchURIList = exactMatchURIList; +} +public List getCloseMatchURIList() { + return closeMatchURIList; +} +public void setCloseMatchURIList(List closeMatchURIList) { + this.closeMatchURIList = closeMatchURIList; +} + +public List getAltLabelList() { + return altLabelList; +} + +public void setAltLabelList(List altLabelList) { + this.altLabelList = altLabelList; +} + +} diff --git a/api/src/main/java/edu/cornell/mannlib/semservices/bo/ConceptInfo.java b/api/src/main/java/edu/cornell/mannlib/semservices/bo/ConceptInfo.java new file mode 100644 index 000000000..3ee08d520 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/semservices/bo/ConceptInfo.java @@ -0,0 +1,32 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.semservices.bo; + + +import java.util.List; + + +public class ConceptInfo extends SemanticServicesInfoBase { + + private List conceptList; + /** + * + */ + public ConceptInfo() { + super(); + } + + /** + * @return the conceptList + */ + public List getConceptList() { + return conceptList; + } + + /** + * @param conceptList the conceptList to set + */ + public void setConceptList(List conceptList) { + this.conceptList = conceptList; + } +} diff --git a/api/src/main/java/edu/cornell/mannlib/semservices/bo/SemanticServicesError.java b/api/src/main/java/edu/cornell/mannlib/semservices/bo/SemanticServicesError.java new file mode 100644 index 000000000..449f5c233 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/semservices/bo/SemanticServicesError.java @@ -0,0 +1,75 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.semservices.bo; + +public class SemanticServicesError { + private String message; + private String exception; + private String severity; + + /** + * + */ + public SemanticServicesError() { + super(); + } + + + + /** + * @param exception Exception description + * @param message Error message + * @param severity Severity + */ + public SemanticServicesError(String exception, String message, String severity) { + super(); + this.exception = exception; + this.message = message; + this.severity = severity; + } + + + + /** + * @return the message + */ + public String getMessage() { + return message; + } + + /** + * @param message the message to set + */ + public void setMessage(String message) { + this.message = message; + } + + /** + * @return the exception + */ + public String getException() { + return exception; + } + + /** + * @param exception the exception to set + */ + public void setException(String exception) { + this.exception = exception; + } + + /** + * @return the severity + */ + public String getSeverity() { + return severity; + } + + /** + * @param severity the severity to set + */ + public void setSeverity(String severity) { + this.severity = severity; + } + +} diff --git a/api/src/main/java/edu/cornell/mannlib/semservices/bo/SemanticServicesInfoBase.java b/api/src/main/java/edu/cornell/mannlib/semservices/bo/SemanticServicesInfoBase.java new file mode 100644 index 000000000..ac24a3ecc --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/semservices/bo/SemanticServicesInfoBase.java @@ -0,0 +1,29 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.semservices.bo; + +public class SemanticServicesInfoBase { + + private SemanticServicesError semanticServicesError; + /** + * + */ + public SemanticServicesInfoBase() { + super(); + // TODO Auto-generated constructor stub + } + + /** + * @return the semanticServicesError + */ + public SemanticServicesError getSemanticServicesError() { + return semanticServicesError; + } + /** + * @param semanticServicesError the semanticServicesError to set + */ + public void setSemanticServicesError(SemanticServicesError semanticServicesError) { + this.semanticServicesError = semanticServicesError; + } + +} diff --git a/api/src/main/java/edu/cornell/mannlib/semservices/exceptions/ConceptsNotFoundException.java b/api/src/main/java/edu/cornell/mannlib/semservices/exceptions/ConceptsNotFoundException.java new file mode 100644 index 000000000..1264905eb --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/semservices/exceptions/ConceptsNotFoundException.java @@ -0,0 +1,15 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.semservices.exceptions; + +public class ConceptsNotFoundException extends Exception { + /** + * An exception that indicates a service could not find a Concept + */ + private static final long serialVersionUID = -4729465393290022840L; + public ConceptsNotFoundException() { } + public ConceptsNotFoundException(String message) { super(message); } + public ConceptsNotFoundException(Throwable cause) { super(cause); } + public ConceptsNotFoundException(String message, Throwable cause) { super(message, cause); } + +} diff --git a/api/src/main/java/edu/cornell/mannlib/semservices/service/ExternalConceptService.java b/api/src/main/java/edu/cornell/mannlib/semservices/service/ExternalConceptService.java new file mode 100644 index 000000000..8a675a415 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/semservices/service/ExternalConceptService.java @@ -0,0 +1,27 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.semservices.service; + +import java.util.List; + +import edu.cornell.mannlib.semservices.bo.Concept; + +public interface ExternalConceptService { + + /** + * @param term Term + */ + List processResults(String term) throws Exception; + + /** + * @param term Term + * @throws Exception + */ + List getConcepts(String term) throws Exception; + + /** + * @param uri URI + */ + List getConceptsByURIWithSparql(String uri) throws Exception; + +} diff --git a/api/src/main/java/edu/cornell/mannlib/semservices/util/MetadataNamespaceContext.java b/api/src/main/java/edu/cornell/mannlib/semservices/util/MetadataNamespaceContext.java new file mode 100644 index 000000000..b9717e0c2 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/semservices/util/MetadataNamespaceContext.java @@ -0,0 +1,26 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.semservices.util; +import java.util.Iterator; +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; + +public class MetadataNamespaceContext implements NamespaceContext { + public String getNamespaceURI(String prefix) { + if (prefix == null) throw new NullPointerException("Null prefix"); + else if ("mix".equals(prefix)) return "http://www.loc.gov/mix/"; + else if ("xml".equals(prefix)) return XMLConstants.XML_NS_URI; + return XMLConstants.NULL_NS_URI; + } + + // This method isn't necessary for XPath processing. + public String getPrefix(String uri) { + throw new UnsupportedOperationException(); + } + + // This method isn't necessary for XPath processing either. + public Iterator getPrefixes(String uri) { + throw new UnsupportedOperationException(); + } + +} diff --git a/api/src/main/java/edu/cornell/mannlib/semservices/util/SKOSUtils.java b/api/src/main/java/edu/cornell/mannlib/semservices/util/SKOSUtils.java new file mode 100644 index 000000000..1afe48966 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/semservices/util/SKOSUtils.java @@ -0,0 +1,266 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +/* We are no longer using the SKOS API since Vitro has moved to V 4.0 of OWL API which does not appear to be compatible. + This file will contain methods used for reading SKOS as XML and parsing it for the properties + we want to extract*/ + +package edu.cornell.mannlib.semservices.util; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.io.StringWriter; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.NodeIterator; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.ResourceFactory; +import org.apache.jena.rdf.model.Statement; +import org.apache.jena.rdf.model.StmtIterator; + +import edu.cornell.mannlib.semservices.bo.Concept; + +public class SKOSUtils { + protected final static Log log = LogFactory.getLog(SKOSUtils.class); + + public static String getConceptXML(String conceptUriString) { + URL conceptURL = null; + try { + conceptURL = new URL(conceptUriString); + } catch (Exception e) { + log.error("Exception occurred in instantiating URL for " + + conceptUriString, e); + // If the url is having trouble, just return null for the concept + return null; + } + log.debug("loading concept uri " + conceptUriString); + + String results = null; + try { + + StringWriter sw = new StringWriter(); + + BufferedReader in = new BufferedReader(new InputStreamReader( + conceptURL.openStream())); + String inputLine; + while ((inputLine = in.readLine()) != null) { + sw.write(inputLine); + } + in.close(); + + results = sw.toString(); + log.debug(results); + } catch (Exception ex) { + log.error("Error occurred in getting concept from the URL " + + conceptUriString, ex); + return null; + } + return results; + } + + // Downloading the XML from the URI itself + // No language tag support here but can be specified if need be at this + // level as well + public static Concept createConceptUsingXMLFromURL(Concept concept, + String conceptURLString, String langTagValue, boolean addNotes) { + String results = getConceptXML(conceptURLString); + if (StringUtils.isEmpty(results)) { + return null; + } + + // return createConceptUsingXML(concept, results, langTagValue); + return createConceptUsingXMLModel(concept, results, langTagValue, + addNotes); + + } + + // Because of the fact the xml returns matches by tag name, and the XML may + // look like + // where conceptURI is the concept that is the subject of skos:narrower, we + // need to ensure we are not returning the same uri as that of the main + // concept + public static List removeConceptURIFromList(List uris, + String conceptURI) { + // remove will return a boolean if the value exists in the list and is + // removed + // if/when it returns false, the URI is not in the list + while (uris.remove(conceptURI)) { + } + ; + return uris; + } + + /** + * The above code, although functional, does not take advantage of the fact + * that we can actually read and query the RDF in precisely the manner we + * wish. + */ + + public static Concept createConceptUsingXMLModel(Concept concept, + String results, String langTagValue, boolean addNotes) { + + try { + String conceptURI = concept.getUri(); + + // Load Model from RDF + StringReader reader = new StringReader(results); + Model model = ModelFactory.createDefaultModel(); + model.read(reader, null, "RDF/XML"); + + // Execute the following query to get the information we want for + // this resource + + // Preferred label + List labelLiterals = getPrefLabelsFromModel(conceptURI, + model, langTagValue); + if (labelLiterals.size() > 0) { + concept.setLabel(labelLiterals.get(0)); + } else { + // This is an error because there should be at least one label + // returned + log.debug("The number of preferred labels is not greater than zero"); + } + + // Alternate label + + List altLabelList = getAltLabelsFromModel(conceptURI, + model, langTagValue); + concept.setAltLabelList(altLabelList); + + // Broder, narrower, exact match, and close match properties + + List broaderURIList = getBroaderURIsFromModel(conceptURI, + model); + // broaderURIList = removeConceptURIFromList(broaderURIList, + // conceptURI); + concept.setBroaderURIList(broaderURIList); + List narrowerURIList = getNarrowerURIsFromModel(conceptURI, + model); + // narrowerURIList = removeConceptURIFromList(narrowerURIList, + // conceptURI); + concept.setNarrowerURIList(narrowerURIList); + + List exactMatchURIList = getExactMatchURIsFromModel( + conceptURI, model); + // exactMatchURIList = removeConceptURIFromList(exactMatchURIList, + // conceptURI); + concept.setExactMatchURIList(exactMatchURIList); + List closeMatchURIList = getCloseMatchURIsFromModel( + conceptURI, model); + // closeMatchURIList = removeConceptURIFromList(closeMatchURIList, + // conceptURI); + concept.setCloseMatchURIList(closeMatchURIList); + + // Notes may exist, in which case they should be employed + if (addNotes) { + List notes = getNotesFromModel(conceptURI, model, + langTagValue); + if (notes.size() > 0) { + concept.setDefinition(notes.get(0)); + } + } + + } catch (Exception e) { + log.error("error occurred in parsing " + results, e); + } + + return concept; + + } + + private static List getPrefLabelsFromModel(String conceptURI, + Model model, String langTagValue) { + String propertyURI = "http://www.w3.org/2004/02/skos/core#prefLabel"; + return getLabelsFromModel(conceptURI, propertyURI, model, langTagValue); + } + + private static List getAltLabelsFromModel(String conceptURI, + Model model, String langTagValue) { + String propertyURI = "http://www.w3.org/2004/02/skos/core#altLabel"; + return getLabelsFromModel(conceptURI, propertyURI, model, langTagValue); + } + + private static List getLabelsFromModel(String conceptURI, + String propertyURI, Model model, String langTagValue) { + List labels = new ArrayList(); + StmtIterator statements = model.listStatements( + ResourceFactory.createResource(conceptURI), + ResourceFactory.createProperty(propertyURI), (RDFNode) null); + while (statements.hasNext()) { + Statement statement = statements.nextStatement(); + RDFNode node = statement.getObject(); + if (node != null && node.isLiteral()) { + String label = node.asLiteral().getString(); + if (StringUtils.isNotEmpty(langTagValue)) { + String language = node.asLiteral().getLanguage(); + if (language != null && language.equals(langTagValue)) { + labels.add(label); + } + } else { + labels.add(label); + } + } + + } + return labels; + } + + private static List getNotesFromModel(String conceptURI, + Model model, String langTagValue) { + String propertyURI = "http://www.w3.org/2004/02/skos/core#note"; + return getLabelsFromModel(conceptURI, propertyURI, model, langTagValue); + } + + private static List getCloseMatchURIsFromModel(String conceptURI, + Model model) { + String propertyURI = "http://www.w3.org/2004/02/skos/core#closeMatch"; + return getRelatedURIsFromModel(conceptURI, propertyURI, model); + + } + + private static List getExactMatchURIsFromModel(String conceptURI, + Model model) { + String propertyURI = "http://www.w3.org/2004/02/skos/core#exactMatch"; + return getRelatedURIsFromModel(conceptURI, propertyURI, model); + } + + private static List getNarrowerURIsFromModel(String conceptURI, + Model model) { + String propertyURI = "http://www.w3.org/2004/02/skos/core#narrower"; + return getRelatedURIsFromModel(conceptURI, propertyURI, model); + } + + private static List getBroaderURIsFromModel(String conceptURI, + Model model) { + String propertyURI = "http://www.w3.org/2004/02/skos/core#broader"; + return getRelatedURIsFromModel(conceptURI, propertyURI, model); + } + + private static List getRelatedURIsFromModel(String conceptURI, + String propertyURI, Model model) { + List URIs = new ArrayList(); + NodeIterator nodeIterator = model.listObjectsOfProperty( + ResourceFactory.createResource(conceptURI), + ResourceFactory.createProperty(propertyURI)); + + while (nodeIterator.hasNext()) { + RDFNode node = nodeIterator.nextNode(); + if (node.isResource() && node.asResource().getURI() != null) { + String URI = node.asResource().getURI(); + URIs.add(URI); + } + } + + return URIs; + } + +} \ No newline at end of file diff --git a/api/src/main/java/edu/cornell/mannlib/semservices/util/XMLUtils.java b/api/src/main/java/edu/cornell/mannlib/semservices/util/XMLUtils.java new file mode 100644 index 000000000..b5342c5c8 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/semservices/util/XMLUtils.java @@ -0,0 +1,361 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.semservices.util; + +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Convenience Class to parse XML strings to DOM Document for XML contents + * retrieval. + */ +public class XMLUtils { + private static DocumentBuilder parser; + public static Writer writer; + static private String indent = ""; + protected static final Log logger = LogFactory.getLog(XMLUtils.class); + + + /** + * @throws ParserConfigurationException + */ + public static DocumentBuilder getDocumentBuilder() + throws ParserConfigurationException { + if (parser == null) { + // JPT: Remove xerces use + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory + .newInstance(); + documentBuilderFactory.setNamespaceAware(true); + documentBuilderFactory.setValidating(false); + parser = documentBuilderFactory.newDocumentBuilder(); + } + + return parser; + } + + /** + * @param xmlString XML String + * @throws IOException + * @throws SAXException + * @throws ParserConfigurationException + */ + public synchronized static Document parse(String xmlString) + throws IOException, SAXException, ParserConfigurationException { + StringReader reader = new StringReader(xmlString); + InputSource inputSource = new InputSource(reader); + return getDocumentBuilder().parse(inputSource); + } + + /** + * @param stream Input stream + * @throws IOException + * @throws SAXException + * @throws ParserConfigurationException + */ + public synchronized static Document parse(InputStream stream) + throws IOException, SAXException, ParserConfigurationException { + return getDocumentBuilder().parse(stream); + } + + /** + * @param document DOM Document + * @param name Name + */ + public static String getElementByName(Document document, String name) { + NodeList nodes = document.getElementsByTagName(name); + String s = null; + for (int i=0; i < nodes.getLength() ; i++) { + Node node = nodes.item(i); + s = node.getTextContent().trim(); + } + return s; + } + + /** + * @param doc DOM Document + * @throws IOException + */ + @SuppressWarnings("deprecation") + public static void serializeDoc(Document doc) throws IOException { + org.apache.xml.serialize.XMLSerializer serializer = new org.apache.xml.serialize.XMLSerializer(); + serializer.setOutputByteStream(System.out); + serializer.serialize(doc); + } + + @SuppressWarnings("deprecation") + public static String serializeDoctoString(Document doc) throws IOException { + org.apache.xml.serialize.XMLSerializer serializer = new org.apache.xml.serialize.XMLSerializer(); + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + + serializer.setOutputByteStream(bout); + serializer.serialize(doc); + return bout.toString(); + } + + /** + * @param xml XML String + */ + public static void prettyPrint(String xml) { + Source xmlInput = new StreamSource(new StringReader(xml)); + StreamResult xmlOutput = new StreamResult(new StringWriter()); + Transformer transformer = null; + try { + transformer = TransformerFactory.newInstance().newTransformer(); + } catch (TransformerConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (TransformerFactoryConfigurationError e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + //transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "testing.dtd"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + try { + transformer.transform(xmlInput, xmlOutput); + } catch (TransformerException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + String formattedxml=xmlOutput.getWriter().toString(); + System.out.println(formattedxml); + + } + + /** + * @param xml XML String + */ + public static String prettyPrintToString(String xml) { + Source xmlInput = new StreamSource(new StringReader(xml)); + StreamResult xmlOutput = new StreamResult(new StringWriter()); + Transformer transformer = null; + try { + transformer = TransformerFactory.newInstance().newTransformer(); + } catch (TransformerConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (TransformerFactoryConfigurationError e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + //transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "testing.dtd"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + try { + transformer.transform(xmlInput, xmlOutput); + } catch (TransformerException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + String formattedxml=xmlOutput.getWriter().toString(); + return formattedxml; + + } + + /** + * @param node DOM Node + */ + public static void displayNodeInfo(Node node) { + switch (node.getNodeType()) { + case Node.DOCUMENT_NODE: + System.out.println("Document Node "); + break; + case Node.ELEMENT_NODE: + System.out.println("Element Node: "+ node.getNodeName()); + break; + case Node.TEXT_NODE: + System.out.println("Text Node: "+ node.getNodeName()); + break; + case Node.CDATA_SECTION_NODE: + System.out.println("CDATA Section Node: "); + break; + case Node.COMMENT_NODE: + System.out.println("Comment Node "); + break; + case Node.PROCESSING_INSTRUCTION_NODE: + System.out.println("Processing Instruction Node "); + break; + case Node.ENTITY_REFERENCE_NODE: + System.out.println("Entity Reference Node "); + break; + case Node.DOCUMENT_TYPE_NODE: + System.out.println("Document Type Node "); + break; + } + } + + /** + * @param node DOM Node + * @throws IOException + */ + public static void serializeNode(Node node) throws IOException { + if (writer == null) writer = new BufferedWriter(new OutputStreamWriter(System.out)); + + switch (node.getNodeType()) { + case Node.DOCUMENT_NODE: + Document doc = (Document) node; + writer.write("\n"); + + NodeList nodes = node.getChildNodes(); + if (nodes != null) + for (int i = 0; i < nodes.getLength(); i++) + serializeNode(nodes.item(i)); + break; + case Node.ELEMENT_NODE: + String name = node.getNodeName(); + writer.write("<" + name); + NamedNodeMap attributes = node.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + Node current = attributes.item(i); + writer.write(" " + current.getNodeName() + "=\""); + print(current.getNodeValue()); + writer.write("\""); + } + writer.write(">"); + + NodeList children = node.getChildNodes(); + if (children != null) { + //if ((children.item(0) != null) && (children.item(0).getNodeType() == Node.ELEMENT_NODE)) + // writer.write("\n"); + + for (int i = 0; i < children.getLength(); i++) + serializeNode(children.item(i)); + if ((children.item(0) != null) + && (children.item(children.getLength() - 1).getNodeType() == Node.ELEMENT_NODE)) + writer.write(""); + } + + writer.write(""); + break; + case Node.TEXT_NODE: + print(node.getNodeValue()); + break; + case Node.CDATA_SECTION_NODE: + writer.write("CDATA"); + print(node.getNodeValue()); + writer.write(""); + break; + case Node.COMMENT_NODE: + writer.write("\n"); + break; + case Node.PROCESSING_INSTRUCTION_NODE: + writer.write("\n"); + break; + case Node.ENTITY_REFERENCE_NODE: + writer.write("&" + node.getNodeName() + ";"); + break; + case Node.DOCUMENT_TYPE_NODE: + DocumentType docType = (DocumentType) node; + String publicId = docType.getPublicId(); + String systemId = docType.getSystemId(); + String internalSubset = docType.getInternalSubset(); + writer.write("\n"); + break; + } + writer.flush(); + } + + /** + * @param s String + * @throws IOException + */ + private static void print(String s) throws IOException { + if (s == null) + return; + for (int i = 0, len = s.length(); i < len; i++) { + char c = s.charAt(i); + switch (c) { + case '<': + writer.write("<"); + break; + case '>': + writer.write(">"); + break; + case '&': + writer.write("&"); + break; + case '\r': + writer.write(" "); + break; + default: + writer.write(c); + } + } + } + + /** + * @param obj (either a Document or a Node) + * @param expression Expression + * @return string contents + */ + public static Node getNodeWithXpath(Object obj, String expression) { + Object root = null; + if (obj instanceof Document) { + Document doc = (Document) obj; + root = doc.getDocumentElement(); + } else { + root = (Node) obj; + } + + XPath xpath = XPathFactory.newInstance().newXPath(); + xpath.setNamespaceContext(new MetadataNamespaceContext()); + Node result = null; + + try { + result = ((Node) xpath.evaluate(expression, root, XPathConstants.NODE)); + return result; + } catch (XPathExpressionException e) { + logger.error("XPathExpressionException ", e); + return null; + } + } + +}