1
2
3
4
5
6
7
8
9
10
11
12 package sk.uniba.euromath.document;
13 import java.io.IOException;
14 import java.net.MalformedURLException;
15 import java.net.URISyntaxException;
16 import java.net.URL;
17 import java.util.HashMap;
18 import java.util.Map;
19 import javax.xml.parsers.DocumentBuilder;
20 import javax.xml.parsers.DocumentBuilderFactory;
21 import org.apache.xerces.impl.Constants;
22 import org.apache.xerces.jaxp.DocumentBuilderFactoryImpl;
23 import org.apache.xerces.parsers.DOMParser;
24 import org.apache.xerces.xni.Augmentations;
25 import org.apache.xerces.xni.XMLString;
26 import org.apache.xerces.xni.XNIException;
27 import org.eclipse.core.runtime.IPath;
28 import org.w3c.dom.Document;
29 import org.xml.sax.SAXException;
30 import org.xml.sax.SAXNotRecognizedException;
31 import org.xml.sax.SAXNotSupportedException;
32 import sk.uniba.euromath.tools.URLDir;
33 /***
34 * Deserializes the document.
35 * @author Martin Vysny
36 */
37 public final class DocumentFactory {
38 /***
39 * Constructs the factory.
40 */
41 public DocumentFactory() {
42 super();
43 }
44 /***
45 * <p>
46 * Loads an XML from specified location and prepares it for editing. The
47 * steps that has to be taken (in this order) to load document properly:
48 * <ul>
49 * <li>The document is loaded into DOM model, of course :)</li>
50 * <li>Load schema for every namespace used in the document.</li>
51 * <li>add schema-default attributes and/or elements, that weren't in
52 * original document, into DOM model and mark them as default</li>
53 * <li>assign unique ID for every element and text node</li>
54 * <li>load XSLT for every namespace used in the document</li>
55 * </ul>
56 * </p>
57 * <p>
58 * These steps should be taken to load document properly:
59 * <ol>
60 * <li>Obtain an <code>XMLAccess</code> instance.</li>
61 * <li>Optional step: Load local schemas with the
62 * <code>XMLAccess.loadLocalSchema()</code> function.</li>
63 * <li>Call <code>XMLAccess.loadGlobalSchemas()</code> to ensure that for
64 * each namespace there is schema loaded.</li>
65 * <li>Call <code>XMLAccess.validate()</code> to validate the document.
66 * </li>
67 * <li>Fill <code>Selector</code> to select transformers for all
68 * namespaces.</li>
69 * <li>Open view on document via the <code>XMLAccess.openView()</code>
70 * function.</li>
71 * <li>Get transformed (presentation) document via the
72 * <code>XMLAccess.getTransformedReader()</code> reader and display it.
73 * </li>
74 * </ol>
75 * </p>
76 * @param resource the eclipse resource representing the xml file.
77 * @return XMLAccess representation of document.
78 * @throws SAXException when error occurs during document deserialization
79 * @throws IOException when i/o error occurs
80 * @throws DocumentException when error occurs during document processing
81 */
82 public XMLAccess loadDocument(IPath resource) throws SAXException,
83 IOException, DocumentException {
84 return loadDocument(resource.toFile().toURL());
85 }
86 /***
87 * Loads an XML from specified location and prepares it for editing.
88 * @param url the URL address representing the location of the XML document.
89 * @return XMLAccess representation of document.
90 * @throws SAXException when error occurs during document deserialization
91 * @throws IOException when i/o error occurs
92 * @throws DocumentException when error occurs during document processing
93 */
94 public XMLAccess loadDocument(String url) throws SAXException, IOException,
95 DocumentException {
96 return loadDocument(new URL(url));
97 }
98 /***
99 * Loads an XML from specified location and prepares it for editing.
100 * @param url the URL address representing the location of the XML document.
101 * @return XMLAccess representation of document.
102 * @throws SAXException when error occurs during document deserialization
103 * @throws IOException when i/o error occurs
104 * @throws DocumentException when error occurs during document processing
105 */
106 public XMLAccess loadDocument(URL url) throws SAXException, IOException,
107 DocumentException {
108
109 String urlStr = url.toString();
110 int lastSlash = urlStr.lastIndexOf('/');
111 String fileName = urlStr.substring(lastSlash + 1);
112 URLDir rootPath;
113 if (lastSlash < 0) {
114 rootPath = new URLDir();
115 } else {
116 try {
117 rootPath = new URLDir(urlStr.substring(0, lastSlash));
118 } catch (MalformedURLException ex) {
119 throw new Error("Unexpected exception", ex);
120 } catch (URISyntaxException ex) {
121 throw new Error("Unexpected exception", ex);
122 }
123 }
124 Parser parser = new Parser(rootPath);
125 parser.parse(rootPath.getURI().toString() + fileName);
126 Document doc = parser.getDocument();
127 return initDocument(doc, parser.textEntities, rootPath, fileName);
128 }
129 /***
130 * Initializes an <code>XMLAccess</code> instance from given DOM document.
131 * @param doc document to initialize.
132 * @param root URL pointing to the directory where the document is located.
133 * @param fileName the name of the document file, including the extension.
134 * @return initialized instance of XMLAccess.
135 * @throws DocumentException when error occurs during document processing
136 */
137 public XMLAccess newDocument(Document doc, URLDir root, String fileName)
138 throws DocumentException {
139 DomCore dom = new DomCore(doc, null, root, fileName);
140 return new XMLAccess(dom);
141 }
142 /***
143 * Creates <code>XMLAccess</code> instance with empty document.
144 * @param root URL pointing to the directory where the document is located.
145 * @param fileName the name of the document file, including the extension.
146 * @return initialized instance of XMLAccess.
147 * @throws DocumentException when error occurs during document processing
148 */
149 public XMLAccess newDocument(URLDir root, String fileName)
150 throws DocumentException {
151
152 DocumentBuilderFactory factory = new DocumentBuilderFactoryImpl();
153 DocumentBuilder builder;
154 try {
155 builder = factory.newDocumentBuilder();
156 } catch (Exception ex) {
157 throw new Error("Unexpected.", ex);
158 }
159 Document doc = builder.newDocument();
160 DomCore dom = new DomCore(doc, null, root, fileName);
161 return new XMLAccess(dom);
162 }
163 /***
164 * Initializes an <code>XMLAccess</code> instance from given DOM document.
165 * @param doc document to initialize.
166 * @param textEntities all text enities encountered during the parse.
167 * @param root URL pointing to the directory where the document is located.
168 * @param fileName the name of the document file, including the extension.
169 * @return initialized instance of XMLAccess.
170 * @throws DocumentException when error occurs during document processing
171 */
172 private XMLAccess initDocument(Document doc,
173 Map<String, String> textEntities, URLDir root, String fileName)
174 throws DocumentException {
175 final DomCore dom = new DomCore(doc, textEntities, root, fileName);
176 final XMLAccess result = new XMLAccess(dom);
177 return result;
178 }
179 /***
180 * We are going to parse the XML via Xerces's XNI methods. This is the
181 * instance of DOMParser used for parsing documents. With its help we are
182 * going to catch all entity declarations correctly.
183 * @author Martin Vysny
184 */
185 private class Parser extends DOMParser {
186 /***
187 * Contains mapping between the entity name and entity value.
188 */
189 public final Map<String, String> textEntities = new HashMap<String, String>();
190 /***
191 * Constructor.
192 * @param root directory where the document is located.
193 */
194 public Parser(URLDir root) {
195 super();
196 try {
197 setFeature(Constants.SAX_FEATURE_PREFIX
198 + Constants.VALIDATION_FEATURE, false);
199
200 setFeature(Constants.SAX_FEATURE_PREFIX
201 + Constants.NAMESPACES_FEATURE, true);
202
203 setFeature(Constants.XERCES_FEATURE_PREFIX
204 + Constants.INCLUDE_IGNORABLE_WHITESPACE, false);
205 setFeature(Constants.XERCES_FEATURE_PREFIX
206 + Constants.CREATE_ENTITY_REF_NODES_FEATURE, true);
207 setFeature(Constants.XERCES_FEATURE_PREFIX
208 + Constants.INCLUDE_COMMENTS_FEATURE, true);
209 setFeature(Constants.XERCES_FEATURE_PREFIX
210 + Constants.CREATE_CDATA_NODES_FEATURE, true);
211 setFeature(Constants.XERCES_FEATURE_PREFIX
212 + Constants.LOAD_DTD_GRAMMAR_FEATURE, false);
213 } catch (SAXNotRecognizedException ex) {
214 throw new Error(ex);
215 } catch (SAXNotSupportedException ex) {
216 throw new Error(ex);
217 }
218 setEntityResolver(new EmEntityResolver(root));
219 }
220
221
222
223
224 @Override
225 public void reset() throws XNIException {
226 textEntities.clear();
227 super.reset();
228 }
229
230
231
232
233
234
235 @Override
236 public void internalEntityDecl(String name, XMLString text,
237 XMLString nonNormalizedText, Augmentations augs)
238 throws XNIException {
239 if (name.charAt(0) != '%') {
240
241
242 textEntities.put(name.intern(), text.toString().intern());
243 }
244 super.internalEntityDecl(name, text, nonNormalizedText, augs);
245 }
246 }
247 }