001package edu.pdx.cs410J.grader.gradebook; 002 003import org.w3c.dom.*; 004import org.xml.sax.*; 005 006import javax.xml.transform.*; 007import javax.xml.transform.dom.DOMSource; 008import javax.xml.transform.stream.StreamResult; 009import java.io.*; 010import java.net.URL; 011import java.time.format.DateTimeFormatter; 012import java.util.ArrayList; 013import java.util.List; 014 015/** 016 * This class contains fields and methods that are useful when dealing 017 * with XML data. 018 */ 019public class XmlHelper implements EntityResolver, ErrorHandler { 020 021 /** The System ID for the Grade Book DTD */ 022 protected static final String systemID = 023 "http://www.cs.pdx.edu/~whitlock/dtds/gradebook.dtd"; 024 025 /** The Public ID for the Grade Bookd DTD */ 026 protected static final String publicID = 027 "-//Portland State University//DTD CS410J Grade Book//EN"; 028 029 protected static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ISO_LOCAL_DATE_TIME; 030 031 public static byte[] getBytesForXmlDocument(Document xmlDoc) throws TransformerException { 032 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 033 PrintWriter pw = 034 new PrintWriter(new OutputStreamWriter(baos), true); 035 writeXmlToPrintWriter(xmlDoc, pw); 036 return baos.toByteArray(); 037 } 038 039 //////////////////// EntityResolver Methods ////////////////// 040 041 /** 042 * Attempt to resolve the external entity (such as a DTD) described 043 * by the given public and system ID. The external entity is 044 * returned as a <code>InputSource</code> 045 */ 046 @Override 047 public InputSource resolveEntity (String publicId, String systemId) 048 throws SAXException, IOException { 049 050 if (publicId != null && publicId.equals(XmlHelper.publicID)) { 051 // We're resolving the external entity for the Grade Book's 052 // DTD. Check to see if its in the jar file. This way we don't 053 // need to go all the way to the website to find the DTD. 054 String location = "/edu/pdx/cs410J/grader/gradebook.dtd"; 055 InputStream stream = 056 this.getClass().getResourceAsStream(location); 057 if (stream != null) { 058 return new InputSource(stream); 059 } 060 } 061 062 // Try to access the DTD using the URL 063 try { 064 URL url = new URL(systemId); 065 InputStream stream = url.openStream(); 066 return new InputSource(stream); 067 068 } catch (Exception ex) { 069 return null; 070 } 071 } 072 073 ////////////////// ErrorHandler Methods //////////////////////// 074 075 @Override 076 public void warning(SAXParseException ex) throws SAXException { 077 // Most warnings are annoying 078 079// String s = "Warning while parsing XML (" + ex.getLineNumber() + 080// ":" + ex.getColumnNumber() + "): " + ex.getMessage(); 081// System.err.println(s); 082 } 083 084 @Override 085 public void error(SAXParseException ex) throws SAXException { 086 String s = "Error while parsing XML (" + ex.getLineNumber() + 087 ":" + ex.getColumnNumber() + "): " + ex.getMessage(); 088 throw new SAXException(s); 089 } 090 091 @Override 092 public void fatalError(SAXParseException ex) throws SAXException { 093 String s = "Fatal error while parsing XML (" + ex.getLineNumber() 094 + ":" + ex.getColumnNumber() + "): " + ex.getMessage(); 095 throw new SAXException(s); 096 } 097 098 /////////////////// Other Helper Methods /////////////////////// 099 100 /** 101 * Extracts a bunch of notes from an <code>Element</code> 102 */ 103 protected static List<String> extractNotesFrom(Element element) { 104 List<String> list = new ArrayList<>(); 105 106 NodeList children = element.getChildNodes(); 107 for (int i = 0; i < children.getLength(); i++) { 108 Node node = children.item(i); 109 if (!(node instanceof Element)) { 110 continue; 111 } 112 113 Element child = (Element) node; 114 if (child.getTagName().equals("note")) { 115 list.add(extractTextFrom(child)); 116 } 117 } 118 119 return list; 120 } 121 122 /** 123 * Extracts the text from an <code>Element</code>. 124 */ 125 protected static String extractTextFrom(Element element) { 126 Text text = (Text) element.getFirstChild(); 127 return (text == null ? "" : text.getData()); 128 } 129 130 static void writeXmlToPrintWriter(Document doc, PrintWriter pw) throws TransformerException { 131 Source src = new DOMSource(doc); 132 Result res = new StreamResult(pw); 133 134 TransformerFactory xFactory = TransformerFactory.newInstance(); 135 Transformer xform = xFactory.newTransformer(); 136 xform.setOutputProperty(OutputKeys.INDENT, "yes"); 137 xform.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "0"); 138 xform.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, systemID); 139 xform.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, publicID); 140 141 // Suppress warnings about "Declared encoding not matching 142 // actual one 143 xform.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 144 145 xform.transform(src, res); 146 } 147}