/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Sam
*/
package com.caucho.quercus.lib.dom;
import com.caucho.quercus.QuercusException;
import com.caucho.quercus.QuercusLineRuntimeException;
import com.caucho.quercus.QuercusRuntimeException;
import com.caucho.quercus.UnimplementedException;
import com.caucho.quercus.annotation.Optional;
import com.caucho.quercus.annotation.ReturnNullAsFalse;
import com.caucho.quercus.env.*;
import com.caucho.util.L10N;
import com.caucho.util.IoUtil;
import com.caucho.vfs.Path;
import com.caucho.vfs.ReadStream;
import com.caucho.vfs.StringStream;
import com.caucho.vfs.TempStream;
import com.caucho.vfs.WriteStream;
import com.caucho.vfs.Vfs;
import com.caucho.xml.XmlPrinter;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DOMDocument
extends DOMNode<Document>
{
private final static L10N L = new L10N(DOMDocument.class);
private final static Logger log
= Logger.getLogger(DOMDocument.class.getName());
private String _encoding;
DOMDocument(DOMImplementation impl, Document document)
{
super(impl, document);
}
public static DOMDocument __construct(Env env,
@Optional("'1.0'") String version,
@Optional String encoding)
{
DOMDocument document = getImpl(env).createDocument();
if (version != null && version.length() > 0)
document.setVersion(version);
if (encoding != null && encoding.length() > 0)
document.setEncoding(encoding);
return document;
}
public void setVersion(String version)
{
_delegate.setXmlVersion(version);
}
public String getEncoding()
{
return _encoding;
}
public void setEncoding(String encoding)
{
_encoding = encoding;
}
public DOMNode adoptNode(DOMNode source)
throws DOMException
{
return wrap(_delegate.adoptNode(source.getDelegate()));
}
public DOMAttr createAttribute(String name)
throws DOMException
{
try {
return wrap(_delegate.createAttribute(name));
}
catch (org.w3c.dom.DOMException ex) {
throw wrap(ex);
}
}
public DOMAttr createAttributeNS(String namespaceURI, String qualifiedName)
throws DOMException
{
try {
return wrap(_delegate.createAttributeNS(namespaceURI, qualifiedName));
}
catch (org.w3c.dom.DOMException ex) {
throw wrap(ex);
}
}
public DOMCDATASection createCDATASection(String data)
{
return wrap(_delegate.createCDATASection(data));
}
public DOMComment createComment(String data)
{
return wrap(_delegate.createComment(data));
}
public DOMDocumentFragment createDocumentFragment()
{
return wrap(_delegate.createDocumentFragment());
}
public DOMElement createElement(String tagName)
throws DOMException
{
try {
return wrap(_delegate.createElement(tagName));
}
catch (org.w3c.dom.DOMException ex) {
throw wrap(ex);
}
}
public DOMElement createElement(String tagName, String textContent)
throws DOMException
{
try {
DOMElement element = createElement(tagName);
element.setTextContent(textContent);
return element;
}
catch (org.w3c.dom.DOMException ex) {
throw wrap(ex);
}
}
public DOMElement createElementNS(String namespaceURI, String tagName)
throws DOMException
{
try {
return wrap(_delegate.createElementNS(namespaceURI, tagName));
}
catch (org.w3c.dom.DOMException ex) {
throw wrap(ex);
}
}
public DOMElement createElementNS(String namespaceURI,
String tagName,
String textContent)
throws DOMException
{
try {
DOMElement element = createElementNS(namespaceURI, tagName);
element.setTextContent(textContent);
return element;
}
catch (org.w3c.dom.DOMException ex) {
throw wrap(ex);
}
}
public DOMEntityReference createEntityReference(String name)
throws DOMException
{
try {
return wrap(_delegate.createEntityReference(name));
}
catch (org.w3c.dom.DOMException ex) {
throw wrap(ex);
}
}
public DOMProcessingInstruction createProcessingInstruction(String target)
throws DOMException
{
try {
return createProcessingInstruction(target, null);
}
catch (org.w3c.dom.DOMException ex) {
throw wrap(ex);
}
}
public DOMProcessingInstruction createProcessingInstruction(String target,
String data)
throws DOMException
{
try {
return wrap(_delegate.createProcessingInstruction(target, data));
}
catch (org.w3c.dom.DOMException ex) {
throw wrap(ex);
}
}
public DOMText createTextNode(String data)
{
return wrap(_delegate.createTextNode(data));
}
public DOMConfiguration getConfig()
{
throw new UnimplementedException();
}
public DOMDocumentType getDoctype()
{
return wrap(_delegate.getDoctype());
}
public DOMElement getDocumentElement()
{
return wrap(_delegate.getDocumentElement());
}
public String getDocumentURI()
{
return _delegate.getDocumentURI();
}
public DOMConfiguration getDomConfig()
{
return wrap(_delegate.getDomConfig());
}
public DOMElement getElementById(String elementId)
{
return wrap(_delegate.getElementById(elementId));
}
public DOMNodeList getElementsByTagName(String name)
{
return wrap(_delegate.getElementsByTagName(name));
}
public DOMNodeList getElementsByTagNameNS(String uri, String name)
{
return wrap(_delegate.getElementsByTagNameNS(uri, name));
}
public boolean getFormatOutput()
{
throw new UnimplementedException();
}
public DOMImplementation getImplementation()
{
return getImpl();
}
public String getInputEncoding()
{
return _delegate.getInputEncoding();
}
public boolean getPreserveWhiteSpace()
{
throw new UnimplementedException();
}
public boolean getRecover()
{
throw new UnimplementedException();
}
public boolean getResolveExternals()
{
throw new UnimplementedException();
}
public boolean getStrictErrorChecking()
{
return _delegate.getStrictErrorChecking();
}
public boolean getSubstituteEntities()
{
throw new UnimplementedException();
}
public boolean getValidateOnParse()
{
throw new UnimplementedException();
}
public String getVersion()
{
return _delegate.getXmlVersion();
}
public String getXmlEncoding()
{
return _delegate.getXmlEncoding();
}
public boolean getXmlStandalone()
{
return _delegate.getXmlStandalone();
}
public String getXmlVersion()
{
return _delegate.getXmlVersion();
}
public DOMNode importNode(DOMNode node)
{
return importNode(node, false);
}
public DOMNode importNode(DOMNode importedNode, boolean deep)
throws DOMException
{
try {
return wrap(_delegate.importNode(importedNode.getDelegate(), deep));
}
catch (org.w3c.dom.DOMException ex) {
throw wrap(ex);
}
}
// XXX: also can be called statically, returns a DOMDocument in that case
public boolean load(Env env, Path path, @Optional Value options)
throws IOException
{
if (options != null)
env.stub(L.l("`{0}' is ignored", "options"));
ReadStream is = null;
try {
is = path.openRead();
getImpl().parseXMLDocument(_delegate, is, path.getPath());
}
catch (SAXException ex) {
env.warning(ex);
return false;
}
catch (IOException ex) {
env.warning(ex);
return false;
}
finally {
if (is != null) {
is.close();
}
}
return true;
}
/**
* @param source A string containing the HTML
*/
// XXX: also can be called statically, returns a DOMDocument in that case
public boolean loadHTML(Env env, String source)
{
ReadStream is = StringStream.open(source);
try {
getImpl().parseHTMLDocument(_delegate, is, null);
_delegate.setXmlStandalone(true);
/**
* XXX:
_delegate.setDoctype(new QDocumentType("html",
"-//W3C//DTD HTML 4.0 Transitional//EN",
"http://www.w3.org/TR/REC-html40/loose.dtd"));
*/
}
catch (SAXException ex) {
env.warning(ex);
return false;
}
catch (IOException ex) {
env.warning(ex);
return false;
}
finally {
if (is != null) {
is.close();
}
}
return true;
}
// XXX: also can be called statically, returns a DOMDocument in that case
public boolean loadHTMLFile(Env env, Path path)
{
ReadStream is = null;
try {
is = path.openRead();
getImpl().parseHTMLDocument(_delegate, is, path.getPath());
_delegate.setXmlStandalone(true);
/**
* XXX:
_delegate.setDoctype(new QDocumentType("html",
"-//W3C//DTD HTML 4.0 Transitional//EN",
"http://www.w3.org/TR/REC-html40/loose.dtd"));
*/
}
catch (SAXException ex) {
env.warning(ex);
return false;
}
catch (IOException ex) {
env.warning(ex);
return false;
}
finally {
if (is != null) {
is.close();
}
}
return true;
}
// XXX: also can be called statically, returns a DOMDocument in that case
public boolean loadXML(Env env, StringValue source, @Optional Value options)
{
if (options != null)
env.stub(L.l("loadXML 'options' is ignored"));
InputStream is = source.toInputStream();
ReadStream in = null;
try {
in = Vfs.openRead(is);
getImpl().parseXMLDocument(_delegate, in, null);
}
catch (SAXException ex) {
env.warning(ex);
return false;
}
catch (IOException ex) {
env.warning(ex);
return false;
}
finally {
IoUtil.close(is);
IoUtil.close(in);
}
return true;
}
public void normalizeDocument()
{
_delegate.normalizeDocument();
}
public boolean relaxNGValidate(String rngFilename)
{
throw new UnimplementedException();
}
public boolean relaxNGValidateSource(String rngSource)
{
throw new UnimplementedException();
}
public DOMNode renameNode(
DOMNode node, String namespaceURI, String qualifiedName)
throws DOMException
{
try {
return wrap(_delegate.renameNode(
node.getDelegate(), namespaceURI, qualifiedName));
}
catch (org.w3c.dom.DOMException ex) {
throw wrap(ex);
}
}
/**
* @return the number of bytes written, or FALSE for an error
*/
public Value save(Env env, Path path, @Optional Value options)
{
if (options != null)
env.stub(L.l("`{0}' is ignored", "options"));
return saveToFile(env, path, false);
}
private Value saveToFile(Env env, Path path, boolean isHTML)
{
WriteStream os = null;
try {
os = path.openWrite();
saveToStream(this, os, isHTML);
}
catch (IOException ex) {
env.warning(ex);
return BooleanValue.FALSE;
}
finally {
if (os != null) {
try {
os.close();
}
catch (Exception ex) {
log.log(Level.FINE, ex.toString(), ex);
}
}
}
return LongValue.create(path.getLength());
}
private void saveToStream(DOMNode delegate, WriteStream os, boolean isHTML)
throws IOException
{
XmlPrinter printer = new XmlPrinter(os);
printer.setMethod(isHTML ? "html" : "xml");
printer.setEncoding(_encoding);
if(delegate._delegate instanceof Document)
{
/*
Print the XML Declaration ( the <?xml thing ) only for Documents,
as they don't make sense when just printing nodes.
*/
printer.setPrintDeclaration(true);
Document document = (Document) delegate._delegate;
printer.setVersion(document.getXmlVersion());
if (document.getXmlStandalone()){
printer.setStandalone("yes");
}
printer.printXml(document);
}
else
{
printer.printXml((org.w3c.dom.Node) delegate._delegate);
}
if (hasChildNodes())
os.println();
}
@ReturnNullAsFalse
public StringValue saveHTML(Env env)
{
return saveToString(env, this, true);
}
private StringValue saveToString(Env env, DOMNode node, boolean isHTML)
{
TempStream tempStream = new TempStream();
try {
tempStream.openWrite();
WriteStream os = new WriteStream(tempStream);
saveToStream(node, os, isHTML);
os.close();
}
catch (IOException ex) {
tempStream.discard();
env.warning(ex);
return null;
}
StringValue result = env.createBinaryString(tempStream.getHead());
tempStream.discard();
return result;
}
/**
* @return the number of bytes written, or FALSE for an error
*/
public Value saveHTMLFile(Env env, Path path)
{
return saveToFile(env, path, true);
}
@ReturnNullAsFalse
public StringValue saveXML(Env env,
@Optional DOMNode node,
@Optional Value options)
throws DOMException
{
if (options != null)
env.stub(L.l("`{0}' is ignored", "options"));
if (node != null) {
// check if node is from another document
if (node.getDelegate().getOwnerDocument() != this._delegate) {
throw new DOMException(getImpl(),
new org.w3c.dom.DOMException(
org.w3c.dom.DOMException.WRONG_DOCUMENT_ERR,
"Wrong Document Error")
);
}
return saveToString(env, node, false);
}
return saveToString(env, this, false);
}
public boolean schemaValidate(String schemaFilename)
{
throw new UnimplementedException();
}
public boolean schemaValidateSource(String schemaSource)
{
throw new UnimplementedException();
}
public void setDocumentURI(String documentURI)
{
_delegate.setDocumentURI(documentURI);
}
public void setFormatOutput(boolean formatOutput)
{
throw new UnimplementedException();
}
public void setPreserveWhiteSpace(boolean preserveWhiteSpace)
{
throw new UnimplementedException();
}
public void setRecover(boolean recover)
{
throw new UnimplementedException();
}
public void setResolveExternals(boolean resolveExternals)
{
throw new UnimplementedException();
}
public void setStrictErrorChecking(boolean strictErrorChecking)
{
_delegate.setStrictErrorChecking(strictErrorChecking);
}
public void setSubstituteEntities(boolean substituteEntities)
{
throw new UnimplementedException();
}
public void setValidateOnParse(boolean validateOnParse)
{
throw new UnimplementedException();
}
public void setXmlStandalone(boolean xmlStandalone)
throws DOMException
{
_delegate.setXmlStandalone(xmlStandalone);
}
public void setXmlVersion(String xmlVersion)
throws DOMException
{
_delegate.setXmlVersion(xmlVersion);
}
public boolean validate()
{
throw new UnimplementedException();
}
public int xinclude(Env env, @Optional Value options)
{
if (options != null)
env.stub(L.l("`{0}' is ignored", "options"));
throw new UnimplementedException();
}
}