Lines 1-603
Link Here
|
1 |
/* |
|
|
2 |
* Copyright 1999-2004 The Apache Software Foundation |
3 |
* |
4 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
5 |
* you may not use this file except in compliance with the License. |
6 |
* You may obtain a copy of the License at |
7 |
* |
8 |
* http://www.apache.org/licenses/LICENSE-2.0 |
9 |
* |
10 |
* Unless required by applicable law or agreed to in writing, software |
11 |
* distributed under the License is distributed on an "AS IS" BASIS, |
12 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 |
* See the License for the specific language governing permissions and |
14 |
* limitations under the License. |
15 |
* |
16 |
*/ |
17 |
|
18 |
/* $Id$ */ |
19 |
|
20 |
package org.apache.lenya.xml; |
21 |
|
22 |
|
23 |
import java.io.File; |
24 |
import java.io.FileOutputStream; |
25 |
import java.io.IOException; |
26 |
import java.io.InputStream; |
27 |
import java.io.OutputStream; |
28 |
import java.net.URL; |
29 |
import java.util.Properties; |
30 |
import java.util.StringTokenizer; |
31 |
import java.util.Vector; |
32 |
|
33 |
import org.apache.lenya.net.ProxyManager; |
34 |
import org.apache.log4j.Category; |
35 |
import org.w3c.dom.Document; |
36 |
import org.w3c.dom.Element; |
37 |
import org.w3c.dom.Node; |
38 |
import org.w3c.dom.NodeList; |
39 |
|
40 |
|
41 |
/** |
42 |
* XLink/XInclude Processor (Nesting, Caching, Java, Exceptions) |
43 |
*/ |
44 |
public class XIncludeImpl implements XInclude { |
45 |
static Category log = Category.getInstance(XIncludeImpl.class); |
46 |
DOMParserFactory dpf = null; |
47 |
XPointerFactory xpf = null; |
48 |
Configuration conf = null; |
49 |
ProxyManager pm = null; |
50 |
String XPSEXCEPTION_ELEMENT_NAME = "XPSEXCEPTION"; // better would be a namespace xps:XLinkException |
51 |
|
52 |
/** |
53 |
* Creates a new XIncludeImpl object. |
54 |
*/ |
55 |
public XIncludeImpl() { |
56 |
dpf = new DOMParserFactory(); |
57 |
xpf = new XPointerFactory(); |
58 |
conf = new Configuration(); |
59 |
pm = new ProxyManager(); |
60 |
|
61 |
if ((conf.proxyHost != null) && (conf.proxyPort != null)) { |
62 |
Properties sp = System.getProperties(); |
63 |
sp.put("proxySet", "true"); |
64 |
sp.put("proxyHost", conf.proxyHost); |
65 |
sp.put("proxyPort", conf.proxyPort); |
66 |
} |
67 |
} |
68 |
|
69 |
/** |
70 |
* Creates a new XIncludeImpl object. |
71 |
* |
72 |
* @param includeoption DOCUMENT ME! |
73 |
*/ |
74 |
public XIncludeImpl(String includeoption) { |
75 |
this(); |
76 |
conf.INCLUDE = includeoption; |
77 |
} |
78 |
|
79 |
/** |
80 |
* DOCUMENT ME! |
81 |
* |
82 |
* @param reference DOCUMENT ME! |
83 |
* @param cocoon DOCUMENT ME! |
84 |
* |
85 |
* @return DOCUMENT ME! |
86 |
*/ |
87 |
public Document assemble(String reference, String cocoon) { |
88 |
File workingDirectory = new File(System.getProperty("user.dir")); |
89 |
XPSSourceInformation sourceInfo = new XPSSourceInformation("file:" + workingDirectory + |
90 |
"/dummy.xml", cocoon); |
91 |
String[] args = new String[1]; |
92 |
args[0] = reference; |
93 |
|
94 |
XPSSourceInformation currentInfo = new XPSSourceInformation(args[0], sourceInfo, cocoon); |
95 |
deleteFromCache(currentInfo.url); |
96 |
|
97 |
Vector nodes = include(args, sourceInfo); |
98 |
log.debug(sourceInfo); |
99 |
|
100 |
Node node = (Node) nodes.elementAt(0); |
101 |
|
102 |
return node.getOwnerDocument(); |
103 |
} |
104 |
|
105 |
/** |
106 |
* Remove file from cache |
107 |
* |
108 |
* @param url DOCUMENT ME! |
109 |
*/ |
110 |
public void deleteFromCache(URL url) { |
111 |
if (conf.cacheFolder != null) { |
112 |
File cacheFile = getCacheFile(url); |
113 |
|
114 |
if (cacheFile.isFile()) { |
115 |
log.info(".deleteFromCache(): " + cacheFile.getAbsolutePath()); |
116 |
cacheFile.delete(); |
117 |
} else { |
118 |
log.warn(".deleteFromCache(): No such file in cache: " + |
119 |
cacheFile.getAbsolutePath()); |
120 |
} |
121 |
} |
122 |
} |
123 |
|
124 |
/** |
125 |
* DOCUMENT ME! |
126 |
* |
127 |
* @param document DOCUMENT ME! |
128 |
* @param reference DOCUMENT ME! |
129 |
* @param cocoon DOCUMENT ME! |
130 |
* |
131 |
* @return DOCUMENT ME! |
132 |
*/ |
133 |
public Document assemble(Document document, String reference, String cocoon) { |
134 |
//return document; |
135 |
Element root = document.getDocumentElement(); |
136 |
Document assembledDocument = dpf.getDocument(); |
137 |
Element assembledRoot = (Element) dpf.cloneNode(assembledDocument, root, false); |
138 |
assembledDocument.appendChild(assembledRoot); |
139 |
|
140 |
File workingDirectory = new File(System.getProperty("user.dir")); |
141 |
XPSSourceInformation sourceInfo = new XPSSourceInformation("file:" + workingDirectory + "/dummy.xml", cocoon); |
142 |
XPSSourceInformation currentInfo = new XPSSourceInformation(reference, sourceInfo, cocoon); |
143 |
NodeList nl = root.getChildNodes(); |
144 |
|
145 |
for (int i = 0; i < nl.getLength(); i++) { |
146 |
traverse(assembledRoot, nl.item(i), sourceInfo, currentInfo); |
147 |
} |
148 |
|
149 |
return assembledDocument; |
150 |
} |
151 |
|
152 |
/** |
153 |
* DOCUMENT ME! |
154 |
* |
155 |
* @param currentInfo DOCUMENT ME! |
156 |
* |
157 |
* @return DOCUMENT ME! |
158 |
* |
159 |
* @throws Exception DOCUMENT ME! |
160 |
*/ |
161 |
public InputStream readXML(XPSSourceInformation currentInfo) |
162 |
throws Exception { |
163 |
InputStream is = null; |
164 |
File cacheFile = null; |
165 |
long originalFileLastModified = 0; |
166 |
|
167 |
String protocol = currentInfo.url.getProtocol(); |
168 |
|
169 |
URL url = null; |
170 |
|
171 |
if (conf.cacheFolder != null) // Check cache |
172 |
{ |
173 |
cacheFile = getCacheFile(currentInfo.url); |
174 |
|
175 |
if (protocol.equals("file")) { |
176 |
File originalFile = new File(currentInfo.url.getFile()); |
177 |
originalFileLastModified = originalFile.lastModified(); |
178 |
} else if (protocol.equals("http")) { |
179 |
pm.set(currentInfo.url.getHost()); // install proxy if necessary |
180 |
originalFileLastModified = currentInfo.url.openConnection().getLastModified(); |
181 |
} else { |
182 |
log.error("No such protocol: " + protocol); |
183 |
} |
184 |
|
185 |
if (cacheFile.isFile() && (cacheFile.lastModified() >= originalFileLastModified)) { |
186 |
// File already exists in cache and is newer than original File |
187 |
url = new URL("file:" + cacheFile.getAbsolutePath()); |
188 |
} else { // File does not exist in cache |
189 |
url = new URL(currentInfo.url.toString()); |
190 |
} |
191 |
} else { // No cache folder specified |
192 |
url = new URL(currentInfo.url.toString()); |
193 |
} |
194 |
|
195 |
// Read Document |
196 |
is = url.openStream(); |
197 |
|
198 |
return is; |
199 |
} |
200 |
|
201 |
/** |
202 |
* DOCUMENT ME! |
203 |
* |
204 |
* @param currentInfo DOCUMENT ME! |
205 |
* @param newDocument DOCUMENT ME! |
206 |
* |
207 |
* @return DOCUMENT ME! |
208 |
*/ |
209 |
public boolean tryWritingToCache(XPSSourceInformation currentInfo, Document newDocument) { |
210 |
File cacheFile = null; |
211 |
|
212 |
if (conf.cacheFolder != null) // Check cache |
213 |
{ |
214 |
cacheFile = getCacheFile(currentInfo.url); |
215 |
} |
216 |
|
217 |
if (cacheFile != null) { |
218 |
String protocol = currentInfo.url.getProtocol(); |
219 |
|
220 |
if (!cacheFile.exists()) { // Write "Xlink" to cache |
221 |
|
222 |
return writeToCache(protocol, cacheFile, newDocument); |
223 |
} else { // cacheFile exists |
224 |
|
225 |
long originalFileLastModified = 0; |
226 |
String p = currentInfo.url.getProtocol(); |
227 |
|
228 |
if (p.equals("file")) { |
229 |
File originalFile = new File(currentInfo.url.getFile()); |
230 |
originalFileLastModified = originalFile.lastModified(); |
231 |
} else if (p.equals("http")) { |
232 |
try { |
233 |
originalFileLastModified = currentInfo.url.openConnection().getLastModified(); |
234 |
} catch (IOException e) { |
235 |
log.error("originalFileLastModified: " + e); |
236 |
} |
237 |
} else { |
238 |
log.error("No such protocol: " + p); |
239 |
} |
240 |
|
241 |
if (cacheFile.lastModified() < originalFileLastModified) { |
242 |
// File in cache is older than original File |
243 |
return writeToCache(protocol, cacheFile, newDocument); |
244 |
} |
245 |
} |
246 |
} |
247 |
|
248 |
return false; |
249 |
} |
250 |
|
251 |
/** |
252 |
* param args args[0]=url |
253 |
* |
254 |
* @param args DOCUMENT ME! |
255 |
* @param sourceInfo DOCUMENT ME! |
256 |
* |
257 |
* @return DOCUMENT ME! |
258 |
*/ |
259 |
public Vector include(String[] args, XPSSourceInformation sourceInfo) { |
260 |
XPSSourceInformation currentInfo = new XPSSourceInformation(args[0], sourceInfo, sourceInfo.cocoon); |
261 |
|
262 |
sourceInfo.addChild(currentInfo); |
263 |
|
264 |
if (currentInfo.checkLoop(sourceInfo, currentInfo.url)) { |
265 |
log.warn("Loop detected: " + sourceInfo.url.getFile() + " " + currentInfo.url.getFile()); |
266 |
return null; |
267 |
} |
268 |
|
269 |
Document document = null; |
270 |
Vector nodes = new Vector(); |
271 |
Document newDocument = dpf.getDocument(); |
272 |
|
273 |
try { |
274 |
InputStream is = readXML(currentInfo); |
275 |
document = dpf.getDocument(is); |
276 |
} catch (Exception e) { |
277 |
log.warn(e + ", currentInfo: " + currentInfo.url.getFile() + " , sourceInfo: " + sourceInfo.url.getFile()); |
278 |
|
279 |
Element newRoot = dpf.newElementNode(newDocument, XPSEXCEPTION_ELEMENT_NAME); |
280 |
newRoot.appendChild(dpf.newTextNode(newDocument, "" + e)); |
281 |
nodes.addElement(newRoot); |
282 |
|
283 |
return nodes; |
284 |
} |
285 |
|
286 |
Element root = document.getDocumentElement(); |
287 |
Element newRoot = (Element) dpf.cloneNode(newDocument, root, false); |
288 |
newDocument.appendChild(newRoot); |
289 |
|
290 |
NodeList nl = root.getChildNodes(); |
291 |
|
292 |
for (int i = 0; i < nl.getLength(); i++) { |
293 |
traverse(newRoot, nl.item(i), sourceInfo, currentInfo); |
294 |
} |
295 |
|
296 |
boolean writtenToCache = tryWritingToCache(currentInfo, newDocument); |
297 |
|
298 |
if (currentInfo.url.getRef() == null) { |
299 |
log.debug("No XPointer. Return the root node in order to add the whole document."); |
300 |
nodes.addElement(newRoot); |
301 |
} else { |
302 |
log.debug("XPointer: " + currentInfo.url.getRef()); |
303 |
try { |
304 |
nodes = xpf.select(newRoot, currentInfo.url.getRef()); |
305 |
|
306 |
for (int i = 0; i < nodes.size(); i++) { |
307 |
short nodeType = ((Node) nodes.elementAt(i)).getNodeType(); |
308 |
|
309 |
switch (nodeType) { |
310 |
case Node.ELEMENT_NODE: |
311 |
break; |
312 |
|
313 |
case Node.ATTRIBUTE_NODE: { |
314 |
Node attribute = (Node) nodes.elementAt(i); |
315 |
nodes.removeElementAt(i); |
316 |
nodes.insertElementAt(dpf.newTextNode(attribute.getOwnerDocument(), |
317 |
attribute.getNodeValue()), i); |
318 |
|
319 |
break; |
320 |
} |
321 |
|
322 |
default: { |
323 |
log.error(".include(): Node Type (" + nodeType + ") can't be a child of Element"); |
324 |
nodes.removeElementAt(i); |
325 |
|
326 |
break; |
327 |
} |
328 |
} |
329 |
} |
330 |
} catch (Exception e) { |
331 |
log.error("", e); |
332 |
} |
333 |
} |
334 |
|
335 |
return nodes; |
336 |
} |
337 |
|
338 |
/** |
339 |
* Traverses recursively and looks for XLinks and includes the returned NodeList |
340 |
* |
341 |
* @param newParent DOCUMENT ME! |
342 |
* @param orgChild DOCUMENT ME! |
343 |
* @param sourceInfo DOCUMENT ME! |
344 |
* @param currentInfo DOCUMENT ME! |
345 |
*/ |
346 |
public void traverse(Node newParent, Node orgChild, XPSSourceInformation sourceInfo, |
347 |
XPSSourceInformation currentInfo) { |
348 |
Vector newChildren = new Vector(); |
349 |
short nodeType = orgChild.getNodeType(); |
350 |
boolean noXLink = true; |
351 |
|
352 |
switch (nodeType) { |
353 |
case Node.ELEMENT_NODE: { |
354 |
XLink xlink = new XLink((Element) orgChild); |
355 |
|
356 |
if (xlink.href == null) { |
357 |
Element newElement = (Element) dpf.cloneNode(newParent.getOwnerDocument(), orgChild, false); |
358 |
newChildren.addElement(newElement); |
359 |
} else { |
360 |
noXLink = false; |
361 |
log.debug(".traverse(): xlink:href=\"" + xlink.href + "\""); |
362 |
|
363 |
NodeList nl = processXLink(xlink, (Element) orgChild, currentInfo); |
364 |
|
365 |
for (int i = 0; i < nl.getLength(); i++) { |
366 |
newChildren.addElement(dpf.cloneNode(newParent.getOwnerDocument(), nl.item(i), true)); |
367 |
} |
368 |
} |
369 |
|
370 |
break; |
371 |
} |
372 |
|
373 |
case Node.COMMENT_NODE: { |
374 |
newChildren.addElement(dpf.newCommentNode(newParent.getOwnerDocument(), orgChild.getNodeValue())); |
375 |
|
376 |
break; |
377 |
} |
378 |
|
379 |
case Node.TEXT_NODE: { |
380 |
newChildren.addElement(dpf.newTextNode(newParent.getOwnerDocument(), orgChild.getNodeValue())); |
381 |
|
382 |
break; |
383 |
} |
384 |
|
385 |
case Node.CDATA_SECTION_NODE: { |
386 |
newChildren.addElement(dpf.newCDATASection(newParent.getOwnerDocument(), orgChild.getNodeValue())); |
387 |
|
388 |
break; |
389 |
} |
390 |
|
391 |
default: { |
392 |
log.error(".traverse(): Node type not implemented: " + nodeType + " (" + currentInfo.url + ")"); |
393 |
break; |
394 |
} |
395 |
} |
396 |
|
397 |
for (int i = 0; i < newChildren.size(); i++) { |
398 |
newParent.appendChild((Node) newChildren.elementAt(i)); |
399 |
} |
400 |
|
401 |
if (orgChild.hasChildNodes() && noXLink) { |
402 |
NodeList nl = orgChild.getChildNodes(); |
403 |
|
404 |
for (int i = 0; i < nl.getLength(); i++) { |
405 |
traverse((Node) newChildren.elementAt(0), nl.item(i), sourceInfo, currentInfo); |
406 |
} |
407 |
} |
408 |
} |
409 |
|
410 |
/** |
411 |
* Process XLink |
412 |
* |
413 |
* @param xlink DOCUMENT ME! |
414 |
* @param orgChild DOCUMENT ME! |
415 |
* @param currentInfo DOCUMENT ME! |
416 |
* |
417 |
* @return DOCUMENT ME! |
418 |
*/ |
419 |
public NodeList processXLink(XLink xlink, Element orgChild, XPSSourceInformation currentInfo) { |
420 |
NodeList nl = null; |
421 |
|
422 |
// NOTE: if no show attribute is specified, then the value will be set to "undefined" |
423 |
if (!(xlink.show.equals("embed") || xlink.show.equals("enclose") || xlink.show.equals("replace"))) { |
424 |
log.warn("No such value of attribute \"show\" implemented: " + xlink.show); |
425 |
nl = noNodesReturnedFromXLink(xlink); |
426 |
} else { |
427 |
Vector args = new Vector(); |
428 |
String includeClassName = includeClassName(xlink.href, args); |
429 |
String[] arguments = new String[args.size()]; |
430 |
|
431 |
for (int i = 0; i < args.size(); i++) { |
432 |
arguments[i] = (String) args.elementAt(i); |
433 |
log.debug("Arguments: " + arguments[i]); |
434 |
} |
435 |
|
436 |
Vector newChildren = null; |
437 |
|
438 |
try { |
439 |
if (includeClassName.equals(this.getClass().getName())) { |
440 |
newChildren = include(arguments, currentInfo); |
441 |
} else { |
442 |
Class includeClass = Class.forName(includeClassName); |
443 |
XInclude xpsInclude = (XInclude) includeClass.newInstance(); |
444 |
newChildren = xpsInclude.include(arguments, currentInfo); |
445 |
} |
446 |
} catch (Exception e) { |
447 |
log.error(".processXLink(): " + e); |
448 |
} |
449 |
|
450 |
if (newChildren != null) // Returned nodes from XLink |
451 |
{ |
452 |
if (newChildren.size() > 0) { |
453 |
Node firstChild = (Node) newChildren.elementAt(0); |
454 |
Document xlinkedDocument = firstChild.getOwnerDocument(); |
455 |
Element dummyRoot = dpf.newElementNode(xlinkedDocument, "DummyRoot"); |
456 |
|
457 |
if (xlink.show.equals("embed")) { |
458 |
//if (conf.INCLUDE.equals("embed")) { |
459 |
// WARNING: embed was actually meant to also include the actual xlink, but |
460 |
// it was never really implemented and hence led to the misinterpretation of replace |
461 |
// Therefore we treat it the same as replace |
462 |
//dummyRoot.appendChild(xlink.getXLink(xlinkedDocument, dpf)); |
463 |
|
464 |
for (int i = 0; i < newChildren.size(); i++) { |
465 |
dummyRoot.appendChild((Node) newChildren.elementAt(i)); |
466 |
} |
467 |
} else if (xlink.show.equals("replace")) { |
468 |
//} else if (conf.INCLUDE.equals("replace")) { |
469 |
for (int i = 0; i < newChildren.size(); i++) { |
470 |
dummyRoot.appendChild((Node) newChildren.elementAt(i)); |
471 |
} |
472 |
} else if (xlink.show.equals("enclose")) { |
473 |
//} else if (conf.INCLUDE.equals("enclose")) { |
474 |
Element xlinkCopy = xlink.getXLink(xlinkedDocument, dpf); |
475 |
|
476 |
for (int i = 0; i < newChildren.size(); i++) { |
477 |
xlinkCopy.appendChild((Node) newChildren.elementAt(i)); |
478 |
} |
479 |
dummyRoot.appendChild(xlinkCopy); |
480 |
} else { |
481 |
log.warn("No such attribute \"show\" or such value of attribute \"show\" implemented"); |
482 |
} |
483 |
|
484 |
nl = dummyRoot.getChildNodes(); |
485 |
} |
486 |
} |
487 |
|
488 |
if (nl == null) { |
489 |
nl = noNodesReturnedFromXLink(xlink); |
490 |
} |
491 |
|
492 |
if (nl.getLength() == 0) { |
493 |
nl = noNodesReturnedFromXLink(xlink); |
494 |
} |
495 |
} |
496 |
|
497 |
return nl; |
498 |
} |
499 |
|
500 |
/** |
501 |
* DOCUMENT ME! |
502 |
* |
503 |
* @param xlink DOCUMENT ME! |
504 |
* |
505 |
* @return DOCUMENT ME! |
506 |
*/ |
507 |
public NodeList noNodesReturnedFromXLink(XLink xlink) { |
508 |
log.warn("No nodes returned from XLink: " + xlink); |
509 |
|
510 |
Document dummyDocument = dpf.getDocument(); |
511 |
Element dummyRoot = dpf.newElementNode(dummyDocument, "DummyRoot"); |
512 |
Element element = xlink.getXLink(dummyDocument, dpf); |
513 |
dummyRoot.appendChild(element); |
514 |
|
515 |
Element exceptionElement = dpf.newElementNode(dummyDocument, XPSEXCEPTION_ELEMENT_NAME); |
516 |
exceptionElement.appendChild(dpf.newElementNode(dummyDocument, "NoNodesReturnedFromXLink")); |
517 |
dummyRoot.appendChild(exceptionElement); |
518 |
|
519 |
return dummyRoot.getChildNodes(); |
520 |
} |
521 |
|
522 |
/** |
523 |
* DOCUMENT ME! |
524 |
* |
525 |
* @param href DOCUMENT ME! |
526 |
* @param args DOCUMENT ME! |
527 |
* |
528 |
* @return DOCUMENT ME! |
529 |
*/ |
530 |
public String includeClassName(String href, Vector args) { |
531 |
String icn = null; |
532 |
|
533 |
if (href.indexOf(conf.JAVA_ZONE) == 0) { |
534 |
log.debug(".includeClassName(): java class: " + href); |
535 |
icn = href.substring(conf.JAVA_ZONE.length(), href.length()); |
536 |
|
537 |
StringTokenizer st = new StringTokenizer(icn, "?"); |
538 |
icn = st.nextToken(); |
539 |
|
540 |
if (st.countTokens() == 1) { |
541 |
args.addElement(st.nextToken()); |
542 |
} |
543 |
} else { |
544 |
icn = this.getClass().getName(); |
545 |
args.addElement(href); |
546 |
} |
547 |
|
548 |
log.debug(".includeClassName(): class name: " + icn); |
549 |
|
550 |
return icn; |
551 |
} |
552 |
|
553 |
/** |
554 |
* DOCUMENT ME! |
555 |
* |
556 |
* @param url DOCUMENT ME! |
557 |
* |
558 |
* @return DOCUMENT ME! |
559 |
*/ |
560 |
public File getCacheFile(URL url) { |
561 |
String cacheFile = null; |
562 |
String protocol = url.getProtocol(); |
563 |
|
564 |
if (protocol.equals("file")) { |
565 |
cacheFile = protocol + "/" + url.getFile(); |
566 |
} else if (protocol.equals("http")) { |
567 |
cacheFile = protocol + "/" + url.getHost() + "/" + url.getPort() + "/" + url.getFile(); |
568 |
} else { |
569 |
log.error("No such protocol: " + protocol); |
570 |
} |
571 |
|
572 |
return new File(conf.cacheFolder + "/" + cacheFile); |
573 |
} |
574 |
|
575 |
/** |
576 |
* |
577 |
*/ |
578 |
public boolean writeToCache(String protocol, File cacheFile, Document newDocument) { |
579 |
if (protocol.equals("http") && !conf.cacheHTTP) { |
580 |
// Do not cache HTTP |
581 |
return false; |
582 |
} |
583 |
|
584 |
File cacheFileParent = new File(cacheFile.getParent()); |
585 |
|
586 |
if (!cacheFileParent.isDirectory()) { |
587 |
cacheFileParent.mkdirs(); |
588 |
} |
589 |
|
590 |
try { |
591 |
OutputStream out = new FileOutputStream(cacheFile.getAbsolutePath()); |
592 |
|
593 |
new DOMWriter(out, "iso-8859-1").printWithoutFormatting(newDocument); |
594 |
out.close(); |
595 |
|
596 |
return true; |
597 |
} catch (Exception e) { |
598 |
log.error(".include(): " + e); |
599 |
} |
600 |
|
601 |
return false; |
602 |
} |
603 |
} |