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.eclipse.core.runtime.IPath;
22 import org.w3c.dom.Document;
23 import org.xml.sax.SAXException;
24 import org.xml.sax.SAXNotRecognizedException;
25 import org.xml.sax.SAXNotSupportedException;
26 import com.sun.org.apache.xerces.internal.impl.Constants;
27 import com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl;
28 import com.sun.org.apache.xerces.internal.parsers.DOMParser;
29 import com.sun.org.apache.xerces.internal.xni.Augmentations;
30 import com.sun.org.apache.xerces.internal.xni.XMLString;
31 import com.sun.org.apache.xerces.internal.xni.XNIException;
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 return new XMLAccess(doc, null, root, fileName);
140 }
141 /***
142 * Creates <code>XMLAccess</code> instance with empty document.
143 * @param root URL pointing to the directory where the document is located.
144 * @param fileName the name of the document file, including the extension.
145 * @return initialized instance of XMLAccess.
146 * @throws DocumentException when error occurs during document processing
147 */
148 public XMLAccess newDocument(URLDir root, String fileName)
149 throws DocumentException {
150
151 DocumentBuilderFactory factory = new DocumentBuilderFactoryImpl();
152 DocumentBuilder builder;
153 try {
154 builder = factory.newDocumentBuilder();
155 } catch (Exception ex) {
156 throw new Error("Unexpected.", ex);
157 }
158 final Document doc = builder.newDocument();
159 return new XMLAccess(doc, null, root, fileName);
160 }
161 /***
162 * Initializes an <code>XMLAccess</code> instance from given DOM document.
163 * @param doc document to initialize.
164 * @param textEntities all text enities encountered during the parse.
165 * @param root URL pointing to the directory where the document is located.
166 * @param fileName the name of the document file, including the extension.
167 * @return initialized instance of XMLAccess.
168 * @throws DocumentException when error occurs during document processing
169 */
170 private XMLAccess initDocument(Document doc,
171 Map<String, String> textEntities, URLDir root, String fileName)
172 throws DocumentException {
173 final XMLAccess result = new XMLAccess(doc, textEntities, root, fileName);
174 return result;
175 }
176 /***
177 * We are going to parse the XML via Xerces's XNI methods. This is the
178 * instance of DOMParser used for parsing documents. With its help we are
179 * going to catch all entity declarations correctly.
180 * @author Martin Vysny
181 */
182 private class Parser extends DOMParser {
183 /***
184 * Contains mapping between the entity name and entity value.
185 */
186 public final Map<String, String> textEntities = new HashMap<String, String>();
187 /***
188 * Constructor.
189 * @param root directory where the document is located.
190 */
191 public Parser(URLDir root) {
192 super();
193 try {
194 setFeature(Constants.SAX_FEATURE_PREFIX
195 + Constants.VALIDATION_FEATURE, false);
196
197 setFeature(Constants.SAX_FEATURE_PREFIX
198 + Constants.NAMESPACES_FEATURE, true);
199
200 setFeature(Constants.XERCES_FEATURE_PREFIX
201 + Constants.INCLUDE_IGNORABLE_WHITESPACE, false);
202 setFeature(Constants.XERCES_FEATURE_PREFIX
203 + Constants.CREATE_ENTITY_REF_NODES_FEATURE, true);
204 setFeature(Constants.XERCES_FEATURE_PREFIX
205 + Constants.INCLUDE_COMMENTS_FEATURE, true);
206 setFeature(Constants.XERCES_FEATURE_PREFIX
207 + Constants.CREATE_CDATA_NODES_FEATURE, true);
208 setFeature(Constants.XERCES_FEATURE_PREFIX
209 + Constants.LOAD_DTD_GRAMMAR_FEATURE, false);
210 } catch (SAXNotRecognizedException ex) {
211 throw new Error(ex);
212 } catch (SAXNotSupportedException ex) {
213 throw new Error(ex);
214 }
215 setEntityResolver(new EmEntityResolver(root));
216 }
217
218
219
220
221 @Override
222 public void reset() throws XNIException {
223 textEntities.clear();
224 super.reset();
225 }
226
227
228
229
230
231
232 @Override
233 public void internalEntityDecl(String name, XMLString text,
234 XMLString nonNormalizedText, Augmentations augs)
235 throws XNIException {
236 if (name.charAt(0) != '%') {
237
238
239 textEntities.put(name.intern(), text.toString().intern());
240 }
241 super.internalEntityDecl(name, text, nonNormalizedText, augs);
242 }
243 }
244 }