From 4ececefa7ce4ae77e26f475d3f0d19ae679ca10d Mon Sep 17 00:00:00 2001 From: "sicking%bigfoot.com" Date: Wed, 2 Nov 2005 07:38:45 +0000 Subject: [PATCH] Landing XSLT branch. Tracking bug is 155578, fixes bugs 46633, 54659, 73492, 70369, 85408, 90157, 130161, 109918, 150916 and 170097 * New scriptable interfaces to XSLT * Make HTML-output create real html * cleanup the XSLTProcessor class Patch by sicking, pike and peterv r=sicking/pike, sr=peterv, a=asa --- content/xslt/Makefile.in | 2 +- content/xslt/public/Makefile.in | 60 ++ content/xslt/public/nsIDocumentTransformer.h | 78 ++ content/xslt/public/nsIXSLTException.idl | 53 ++ content/xslt/public/nsIXSLTProcessor.idl | 131 +++ .../xslt/public/nsIXSLTProcessorObsolete.idl | 57 ++ content/xslt/src/main/Makefile.in | 18 +- content/xslt/src/main/transformiix.cpp | 63 +- content/xslt/src/main/txXSLTMarkDriver.cpp | 119 +++ content/xslt/src/xslt/Makefile.in | 7 +- content/xslt/src/xslt/txHTMLOutput.cpp | 3 +- content/xslt/src/xslt/txHTMLOutput.h | 2 +- content/xslt/src/xslt/txMozillaTextOutput.cpp | 324 +++++--- content/xslt/src/xslt/txMozillaTextOutput.h | 79 +- content/xslt/src/xslt/txMozillaXMLOutput.cpp | 416 +++++++--- content/xslt/src/xslt/txMozillaXMLOutput.h | 78 +- .../xslt/src/xslt/txMozillaXSLTProcessor.cpp | 768 ++++++++++++++++++ .../xslt/src/xslt/txMozillaXSLTProcessor.h | 147 ++++ .../src/xslt/txStandaloneXSLTProcessor.cpp | 359 ++++++++ .../xslt/src/xslt/txStandaloneXSLTProcessor.h | 162 ++++ content/xslt/src/xslt/txTextOutput.cpp | 21 +- content/xslt/src/xslt/txTextOutput.h | 38 +- content/xslt/src/xslt/txUnknownHandler.cpp | 139 +++- content/xslt/src/xslt/txUnknownHandler.h | 57 +- content/xslt/src/xslt/txXMLEventHandler.h | 121 +-- content/xslt/src/xslt/txXMLOutput.cpp | 34 +- content/xslt/src/xslt/txXMLOutput.h | 37 +- 27 files changed, 2808 insertions(+), 565 deletions(-) create mode 100644 content/xslt/public/Makefile.in create mode 100644 content/xslt/public/nsIDocumentTransformer.h create mode 100644 content/xslt/public/nsIXSLTException.idl create mode 100644 content/xslt/public/nsIXSLTProcessor.idl create mode 100644 content/xslt/public/nsIXSLTProcessorObsolete.idl create mode 100644 content/xslt/src/main/txXSLTMarkDriver.cpp create mode 100644 content/xslt/src/xslt/txMozillaXSLTProcessor.cpp create mode 100644 content/xslt/src/xslt/txMozillaXSLTProcessor.h create mode 100644 content/xslt/src/xslt/txStandaloneXSLTProcessor.cpp create mode 100644 content/xslt/src/xslt/txStandaloneXSLTProcessor.h diff --git a/content/xslt/Makefile.in b/content/xslt/Makefile.in index 50464aa81aeb..3c0e05b136f0 100755 --- a/content/xslt/Makefile.in +++ b/content/xslt/Makefile.in @@ -21,7 +21,7 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -DIRS = document +DIRS = public document include $(topsrcdir)/config/config.mk diff --git a/content/xslt/public/Makefile.in b/content/xslt/public/Makefile.in new file mode 100644 index 000000000000..70d8fdfc4021 --- /dev/null +++ b/content/xslt/public/Makefile.in @@ -0,0 +1,60 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Peter Van der Beken (original author) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = content +XPIDL_MODULE = content_xslt + +EXPORTS = \ + nsIDocumentTransformer.h \ + nsITransformMediator.h \ + $(NULL) + +XPIDLSRCS = \ + nsIXSLTException.idl \ + nsIXSLTProcessor.idl \ + nsIXSLTProcessorObsolete.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/content/xslt/public/nsIDocumentTransformer.h b/content/xslt/public/nsIDocumentTransformer.h new file mode 100644 index 000000000000..28c83f14466b --- /dev/null +++ b/content/xslt/public/nsIDocumentTransformer.h @@ -0,0 +1,78 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jonas Sicking (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsIDocumentTransformer_h__ +#define nsIDocumentTransformer_h__ + +#include "nsISupports.h" + +class nsIDOMDocument; +class nsIDOMNode; + +#define NS_ITRANSFORMOBSERVER_IID \ + {0xcce88481, 0x6eb3, 0x11d6, \ + { 0xa7, 0xf2, 0x8d, 0x82, 0xcd, 0x2a, 0xf3, 0x7c }} + +class nsITransformObserver : public nsISupports +{ +public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ITRANSFORMOBSERVER_IID) + + NS_IMETHOD OnDocumentCreated(nsIDOMDocument *aResultDocument) = 0; + + NS_IMETHOD OnTransformDone(nsresult aResult, nsIDOMDocument *aResultDocument) = 0; + +}; + +#define NS_IDOCUMENTTRANSFORMER_IID \ + {0x43e5a6c6, 0xa53c, 0x4f97, \ + { 0x91, 0x79, 0x47, 0xf2, 0x46, 0xec, 0xd9, 0xd6 }} + +class nsIDocumentTransformer : public nsISupports +{ +public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IDOCUMENTTRANSFORMER_IID) + + NS_IMETHOD TransformDocument(nsIDOMNode *aSourceDOM, + nsIDOMNode *aStyleDOM, + nsITransformObserver *aObserver, + nsIDOMDocument **_retval) = 0; +}; + +#endif //nsIDocumentTransformer_h__ diff --git a/content/xslt/public/nsIXSLTException.idl b/content/xslt/public/nsIXSLTException.idl new file mode 100644 index 000000000000..0c291d1ad8f7 --- /dev/null +++ b/content/xslt/public/nsIXSLTException.idl @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht, + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIException.idl" +#include "domstubs.idl" + +[scriptable, uuid(e06dfaea-92d5-47f7-a800-c5f5404d8771)] +interface nsIXSLTException : nsIException { + /** + * The node in the stylesheet that triggered the exception. + */ + readonly attribute nsIDOMNode styleNode; + + /** + * The context node, may be null + */ + readonly attribute nsIDOMNode sourceNode; +}; diff --git a/content/xslt/public/nsIXSLTProcessor.idl b/content/xslt/public/nsIXSLTProcessor.idl new file mode 100644 index 000000000000..c9616b0a67b9 --- /dev/null +++ b/content/xslt/public/nsIXSLTProcessor.idl @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht, + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" +#include "domstubs.idl" + +interface nsIVariant; + +[scriptable, uuid(4a91aeb3-4100-43ee-a21e-9866268757c5)] +interface nsIXSLTProcessor : nsISupports +{ + /** + * Import the stylesheet into this XSLTProcessor for transformations. + * + * Note: Changing the DOM of the stylesheet document after it has been + * imported does not affect the processor. It will apply the + * stylesheet as it looked at the time of the call to + * importStylesheet + * + * @param style The root-node of a XSLT stylesheet. This can be either + * a document node or an element node. If a document node + * then the document can contain either a XSLT stylesheet + * or a LRE stylesheet. + * If the argument is an element node it must be the + * xsl:stylesheet (or xsl:transform) element of an XSLT + * stylesheet. + * + * @exception nsIXSLTException + */ + void importStylesheet(in nsIDOMNode style); + + /** + * Transforms the node source applying the stylesheet given by + * the importStylesheet() function. The owner document of the output node + * owns the returned document fragment. + * + * @param source The node to be transformed + * @param output The owner document of this node is used to generate + * the output + * @return DocumentFragment The result of the transformation + * + * @exception nsIXSLTException + */ + nsIDOMDocumentFragment transformToFragment(in nsIDOMNode source, + in nsIDOMDocument output); + + /** + * Transforms the node source applying the stylesheet given by the + * importStylesheet() function. + * + * @param source The node to be transformed + * @param output The owner document of this node is used to generate + * the output + * @return DocumentFragment The result of the transformation + * + * @exception nsIXSLTException + */ + nsIDOMDocument transformToDocument(in nsIDOMNode source); + + /** + * Sets a parameter to be used in the following calls to transformNode. + * + * @param namespaceURI The namespaceURI of the XSLT parameter + * @param localName The local name of the XSLT parameter + * @param value The new value of the XSLT parameter + * + * @exception NS_ERROR_ILLEGAL_VALUE The datatype of value is + * not supported + */ + void setParameter(in DOMString namespaceURI, + in DOMString localName, + in nsIVariant value); + + /** + * Gets a parameter, if set and return null otherwise. + * + * @param namespaceURI The namespaceURI of the XSLT parameter + * @param localName The local name of the XSLT parameter + * @return nsIVariant The value of the XSLT parameter + */ + nsIVariant getParameter(in DOMString namespaceURI, + in DOMString localName); + /** + * Removes a parameter, if set. + * + * @param namespaceURI The namespaceURI of the XSLT parameter + * @param localName The local name of the XSLT parameter + */ + void removeParameter(in DOMString namespaceURI, + in DOMString localName); + + /** + * Removes all set parameters from this nsIXSLTProcessor + */ + void clearParameters(); +}; diff --git a/content/xslt/public/nsIXSLTProcessorObsolete.idl b/content/xslt/public/nsIXSLTProcessorObsolete.idl new file mode 100644 index 000000000000..4ff46ae6f1b4 --- /dev/null +++ b/content/xslt/public/nsIXSLTProcessorObsolete.idl @@ -0,0 +1,57 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Nisheeth Ranjan (original author) + * Peter Van der Beken + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface nsIDOMNode; +interface nsIDOMDocument; + +/** + * DEPRECATED! Don't use this interface! Use nsIXSLTProcessor instead!! + */ + +[scriptable, uuid(3fbff728-2d20-11d3-aef3-00108300ff91)] +interface nsIXSLTProcessorObsolete : nsISupports +{ + void transformDocument(in nsIDOMNode aSourceDOM, + in nsIDOMNode aStyleDOM, + in nsIDOMDocument aOutputDOC, + in nsISupports aObserver); +}; diff --git a/content/xslt/src/main/Makefile.in b/content/xslt/src/main/Makefile.in index 74a925355721..4f44b72b24f1 100644 --- a/content/xslt/src/main/Makefile.in +++ b/content/xslt/src/main/Makefile.in @@ -26,7 +26,14 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -PROGRAM = ../transformiix$(BIN_SUFFIX) +LIBRARY_NAME = tx +FORCE_STATIC_LIB = 1 + +SIMPLE_PROGRAMS = transformiix$(BIN_SUFFIX) +ifdef MARK_INC +SIMPLE_PROGRAMS += txXSLTMarkDriver$(BIN_SUFFIX) +endif +EXTRA_DEPS = $(LIBRARY) REQUIRES = expat \ $(NULL) @@ -109,6 +116,7 @@ OBJS =../base/ArrayList.$(OBJ_SUFFIX) \ ../xslt/txXSLTPatterns.$(OBJ_SUFFIX) \ ../xslt/txPatternParser.$(OBJ_SUFFIX) \ ../xslt/XSLTProcessor.$(OBJ_SUFFIX) \ + ../xslt/txStandaloneXSLTProcessor.$(OBJ_SUFFIX) \ ../xslt/functions/CurrentFunctionCall.$(OBJ_SUFFIX) \ ../xslt/functions/DocumentFunctionCall.$(OBJ_SUFFIX) \ ../xslt/functions/ElementAvailableFnCall.$(OBJ_SUFFIX) \ @@ -118,11 +126,13 @@ OBJS =../base/ArrayList.$(OBJ_SUFFIX) \ ../xslt/functions/txFormatNumberFunctionCall.$(OBJ_SUFFIX) \ ../xslt/functions/txKeyFunctionCall.$(OBJ_SUFFIX) \ ../xslt/util/txNodeSorter.$(OBJ_SUFFIX) \ - ../xslt/util/txXPathResultComparator.$(OBJ_SUFFIX) \ - transformiix.$(OBJ_SUFFIX) + ../xslt/util/txXPathResultComparator.$(OBJ_SUFFIX) CPP_PROG_LINK = 1 EXTRA_LIBS = \ + $(LIB_PREFIX)tx.$(LIB_SUFFIX) \ + $(NULL) +SHARED_LIBRARY_LIBS = \ $(DIST)/lib/$(LIB_PREFIX)expat_s.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)xmltok_s.$(LIB_SUFFIX) \ $(NULL) @@ -133,4 +143,4 @@ INCLUDES += -I$(srcdir)/../xslt -I$(srcdir)/../base -I$(srcdir)/../net \ -I$(srcdir)/../xml -I$(srcdir)/../xml/dom \ -I$(srcdir)/../xml/parser \ -I$(srcdir)/../xpath -I$(srcdir)/../xslt/util \ - -I$(srcdir)/../xslt/functions \ No newline at end of file + -I$(srcdir)/../xslt/functions $(MARK_INC) diff --git a/content/xslt/src/main/transformiix.cpp b/content/xslt/src/main/transformiix.cpp index e96a90e58cd6..e4fb0662fc0a 100644 --- a/content/xslt/src/main/transformiix.cpp +++ b/content/xslt/src/main/transformiix.cpp @@ -29,14 +29,13 @@ * * Olivier Gerardin, ogerardin@vo.lu * -- redirect non-data output (banner, errors) to stderr - * -- read XML from stdin when -i is omitted - * -- accept '-' to specify stdin/stdout on command line * */ -#include "XSLTProcessor.h" +#include "txStandaloneXSLTProcessor.h" #include "CommandLineUtils.h" +#include //--------------/ //- Prototypes -/ @@ -57,13 +56,8 @@ void printUsage(); **/ int main(int argc, char** argv) { - if (!txInit()) + if (!txXSLTProcessor::txInit()) return 1; - XSLTProcessor xsltProcessor; - - //-- add ErrorObserver - SimpleErrorObserver seo; - xsltProcessor.addErrorObserver(seo); //-- available flags StringList flags; @@ -79,8 +73,8 @@ int main(int argc, char** argv) { if (!options.get(String("q"))) { String copyright("(C) 1999 The MITRE Corporation, Keith Visco, and contributors"); - cerr << xsltProcessor.getAppName() << " "; - cerr << xsltProcessor.getAppVersion() << endl; + cerr << "TransforMiiX "; + cerr << "1.2b pre" << endl; cerr << copyright << endl; //-- print banner line PRUint32 fillSize = copyright.length() + 1; @@ -98,63 +92,52 @@ int main(int argc, char** argv) { String* xsltFilename = (String*)options.get(String("s")); String* outFilename = (String*)options.get(String("o")); - - //-- open XML file - istream* xmlInput = &cin; - if (xmlFilename && ! xmlFilename->isEqual("-")) { - xmlInput = new ifstream(NS_LossyConvertUCS2toASCII(*xmlFilename).get(), - ios::in); - } - //-- handle output stream ostream* resultOutput = &cout; ofstream resultFileStream; - if ( outFilename && ! outFilename->isEqual("-")) { + if (outFilename && !outFilename->isEqual("-")) { resultFileStream.open(NS_LossyConvertUCS2toASCII(*outFilename).get(), ios::out); - if ( !resultFileStream ) { + if (!resultFileStream) { cerr << "error opening output file: " << *xmlFilename << endl; return -1; } resultOutput = &resultFileStream; } + SimpleErrorObserver obs; + txStandaloneXSLTProcessor proc; + nsresult rv = NS_OK; //-- process - String documentBase; - if ( !xsltFilename ) { - if (!xmlFilename) { - cerr << "you must specify XSLT file with -s option if XML is read from standard input" << endl; - printUsage(); - return -1; - } - xsltProcessor.process(*xmlInput, *xmlFilename, *resultOutput); + if (!xsltFilename) { + if (!xmlFilename) { + cerr << "you must specify at least a source XML path" << endl; + printUsage(); + return -1; + } + rv = proc.transform(*xmlFilename, *resultOutput, obs); } else { //-- open XSLT file - ifstream xsltInput(NS_LossyConvertUCS2toASCII(*xsltFilename).get(), - ios::in); - xsltProcessor.process(*xmlInput, *xmlFilename, xsltInput, *xsltFilename, *resultOutput); + rv = proc.transform(*xmlFilename, *xsltFilename, *resultOutput, obs); } resultFileStream.close(); - if (xmlInput != &cin) - delete xmlInput; - txShutdown(); - return 0; + txXSLTProcessor::txShutdown(); + return NS_SUCCEEDED(rv); } //-- main void printHelp() { cerr << "transfrmx [-h] [-i xml-file] [-s xslt-file] [-o output-file]" << endl << endl; cerr << "Options:"; cerr << endl << endl; - cerr << "\t-i specify XML file to process (default: read from stdin)" << endl; + cerr << "\t-i specify XML file to process" << endl; cerr << "\t-s specify XSLT file to use for processing (default: use stylesheet" << endl << "\t\tspecified in XML file)" << endl; cerr << "\t-o specify output file (default: write to stdout)" << endl; cerr << "\t-h this help screen" << endl; cerr << endl; - cerr << "You may use '-' in place of xml-file or output-file to explicitly specify" << endl; - cerr << "respectively the standard input and standard output." << endl; - cerr << "If the XML is read from stdin, then the -s option is mandatory." << endl; + cerr << "You may use '-' in place of the output-file to explicitly specify" << endl; + cerr << "standard output." << endl; cerr << endl; } void printUsage() { diff --git a/content/xslt/src/main/txXSLTMarkDriver.cpp b/content/xslt/src/main/txXSLTMarkDriver.cpp new file mode 100644 index 000000000000..7d45c812b58f --- /dev/null +++ b/content/xslt/src/main/txXSLTMarkDriver.cpp @@ -0,0 +1,119 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht (original author) + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * Driver for running XSLTMark on standalone + * + * See http://www.datapower.com/XSLTMark/ + */ + +#include "txStandaloneXSLTProcessor.h" +#include "xmExternalDriver.hpp" + +class txDriverProcessor : public txStandaloneXSLTProcessor, + public xmExternalDriver +{ +public: + txDriverProcessor() : mXSL(0), mXML(0), mOut(0) + { + } + + int loadStylesheet (char * filename) + { + delete mXSL; + mXSL = parsePath(String(filename), mObserver); + return mXSL ? 0 : 1; + } + int setInputDocument (char * filename) + { + delete mXML; + mXML = parsePath(String(filename), mObserver); + return mXML ? 0 : 1; + } + int openOutput (char * outputFilename) + { + mOut = new ofstream(outputFilename); + return mXML ? 0 : 1; + } + int runTransform () + { + nsresult rv = transform(mXML, mXSL, *mOut, mObserver); + return NS_FAILED(rv); + } + int closeOutput () + { + if (mOut) + mOut->close(); + delete mOut; + mOut = 0; + return 0; + } + int terminate() + { + delete mXSL; + mXSL = 0; + delete mXML; + mXML = 0; + if (mOut && mOut->is_open()) + mOut->close(); + delete mOut; + mOut = 0; + return 0; + } + ~txDriverProcessor() + { + delete mXSL; + delete mXML; + delete mOut; + } +private: + Document *mXSL, *mXML; + SimpleErrorObserver mObserver; + ofstream* mOut; +}; + +int main (int argc, char ** argv) +{ + txDriverProcessor driver; + if (!txDriverProcessor::txInit()) + return 1; + driver.main (argc, argv); + txDriverProcessor::txShutdown(); + return 0; +} diff --git a/content/xslt/src/xslt/Makefile.in b/content/xslt/src/xslt/Makefile.in index 931de8701202..31113ade88a9 100644 --- a/content/xslt/src/xslt/Makefile.in +++ b/content/xslt/src/xslt/Makefile.in @@ -42,6 +42,7 @@ REQUIRES = string \ htmlparser \ webshell \ docshell \ + layout \ $(NULL) endif @@ -54,16 +55,18 @@ CPPSRCS = Names.cpp \ txXSLTNumberCounters.cpp \ txXSLTPatterns.cpp \ txPatternParser.cpp \ + txUnknownHandler.cpp \ XSLTProcessor.cpp ifdef TX_EXE CPPSRCS += txHTMLOutput.cpp \ + txStandaloneXSLTProcessor.cpp \ txTextOutput.cpp \ - txUnknownHandler.cpp \ txXMLOutput.cpp else CPPSRCS += txMozillaTextOutput.cpp \ - txMozillaXMLOutput.cpp + txMozillaXMLOutput.cpp \ + txMozillaXSLTProcessor.cpp endif include $(topsrcdir)/config/rules.mk diff --git a/content/xslt/src/xslt/txHTMLOutput.cpp b/content/xslt/src/xslt/txHTMLOutput.cpp index a59b27dc47b1..efe7ae09c5b8 100644 --- a/content/xslt/src/xslt/txHTMLOutput.cpp +++ b/content/xslt/src/xslt/txHTMLOutput.cpp @@ -41,7 +41,8 @@ #include "txOutputFormat.h" #include "XMLUtils.h" -txHTMLOutput::txHTMLOutput() +txHTMLOutput::txHTMLOutput(txOutputFormat* aFormat, ostream* aOut) + : txXMLOutput(aFormat, aOut) { mUseEmptyElementShorthand = MB_FALSE; diff --git a/content/xslt/src/xslt/txHTMLOutput.h b/content/xslt/src/xslt/txHTMLOutput.h index d16a435fc184..ebdc476c5786 100644 --- a/content/xslt/src/xslt/txHTMLOutput.h +++ b/content/xslt/src/xslt/txHTMLOutput.h @@ -46,7 +46,7 @@ class txHTMLOutput : public txXMLOutput { public: - txHTMLOutput(); + txHTMLOutput(txOutputFormat* aFormat, ostream* aOut); ~txHTMLOutput(); /* diff --git a/content/xslt/src/xslt/txMozillaTextOutput.cpp b/content/xslt/src/xslt/txMozillaTextOutput.cpp index 19735c205ef1..7d376e1ec50d 100644 --- a/content/xslt/src/xslt/txMozillaTextOutput.cpp +++ b/content/xslt/src/xslt/txMozillaTextOutput.cpp @@ -37,21 +37,58 @@ * ***** END LICENSE BLOCK ***** */ #include "txMozillaTextOutput.h" +#include "nsContentCID.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIDOMElement.h" #include "nsIDOMHTMLElement.h" #include "nsIDOMText.h" +#include "nsIDocumentTransformer.h" #include "TxString.h" +#include "nsNetUtil.h" +#include "nsIDOMNSDocument.h" -txMozillaTextOutput::txMozillaTextOutput() +static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID); + +txMozillaTextOutput::txMozillaTextOutput(nsIDOMDocument* aSourceDocument, + nsIDOMDocument* aResultDocument, + nsITransformObserver* aObserver) { + NS_INIT_ISUPPORTS(); + + mObserver = do_GetWeakReference(aObserver); + createResultDocument(aSourceDocument, aResultDocument); +} + +txMozillaTextOutput::txMozillaTextOutput(nsIDOMDocumentFragment* aDest) +{ + NS_INIT_ISUPPORTS(); + + nsCOMPtr doc; + aDest->GetOwnerDocument(getter_AddRefs(doc)); + NS_ASSERTION(doc, "unable to get ownerdocument"); + nsCOMPtr textNode; + nsresult rv = doc->CreateTextNode(NS_LITERAL_STRING(""), + getter_AddRefs(textNode)); + if (NS_FAILED(rv)) { + return; + } + nsCOMPtr dummy; + rv = aDest->AppendChild(textNode, getter_AddRefs(dummy)); + if (NS_FAILED(rv)) { + return; + } + + mTextNode = textNode; + return; } txMozillaTextOutput::~txMozillaTextOutput() { } +NS_IMPL_ISUPPORTS1(txMozillaTextOutput, txIOutputXMLEventHandler); + void txMozillaTextOutput::attribute(const String& aName, const PRInt32 aNsID, const String& aValue) @@ -68,12 +105,12 @@ void txMozillaTextOutput::comment(const String& aData) { } -void txMozillaTextOutput::disableStylesheetLoad() -{ -} - void txMozillaTextOutput::endDocument() { + nsCOMPtr observer = do_QueryReferent(mObserver); + if (observer) { + observer->OnTransformDone(NS_OK, mDocument); + } } void txMozillaTextOutput::endElement(const String& aName, @@ -81,36 +118,20 @@ void txMozillaTextOutput::endElement(const String& aName, { } -nsresult txMozillaTextOutput::getRootContent(nsIContent** aReturn) -{ - NS_ASSERTION(aReturn, "NULL pointer passed to getRootContent"); - - *aReturn = mRootContent; - NS_IF_ADDREF(*aReturn); - return NS_OK; -} - -PRBool txMozillaTextOutput::isDone() -{ - return PR_TRUE; -} - void txMozillaTextOutput::processingInstruction(const String& aTarget, const String& aData) { } -void txMozillaTextOutput::removeScriptElement(nsIDOMHTMLScriptElement *aElement) +void txMozillaTextOutput::startDocument() { - NS_NOTREACHED("No script elements in text output, so this is weird!"); } -void txMozillaTextOutput::setOutputDocument(nsIDOMDocument* aDocument) +void txMozillaTextOutput::createResultDocument(nsIDOMDocument* aSourceDocument, + nsIDOMDocument* aResultDocument) { - NS_ASSERTION(aDocument, "Document can't be NULL!"); - if (!aDocument) - return; - + nsresult rv = NS_OK; + /* * Create an XHTML document to hold the text. * @@ -120,92 +141,172 @@ void txMozillaTextOutput::setOutputDocument(nsIDOMDocument* aDocument) *
 * The text comes here * 
* * + * + * Except if we are transforming into a non-displayed document we create + * the following DOM + * + * * The text comes here * */ + + nsCOMPtr doc; + if (!aResultDocument) { + // Create the document + doc = do_CreateInstance(kXMLDocumentCID, &rv); + NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create document"); + mDocument = do_QueryInterface(doc); + } + else { + mDocument = aResultDocument; + doc = do_QueryInterface(aResultDocument); + NS_ASSERTION(doc, "Couldn't QI to nsIDocument"); + } + + if (!doc) { + return; + } + + NS_ASSERTION(mDocument, "Need document"); + + nsCOMPtr nsDoc = do_QueryInterface(mDocument); + if (nsDoc) { + nsDoc->SetTitle(NS_LITERAL_STRING("")); + } + + // Reset and set up document + nsCOMPtr loadGroup; + nsCOMPtr channel; + nsCOMPtr sourceDoc = do_QueryInterface(aSourceDocument); + sourceDoc->GetDocumentLoadGroup(getter_AddRefs(loadGroup)); + nsCOMPtr serv = do_GetService(NS_IOSERVICE_CONTRACTID); + if (serv) { + // Create a temporary channel to get nsIDocument->Reset to + // do the right thing. We want the output document to get + // much of the input document's characteristics. + nsCOMPtr docURL; + sourceDoc->GetDocumentURL(getter_AddRefs(docURL)); + serv->NewChannelFromURI(docURL, getter_AddRefs(channel)); + } + doc->Reset(channel, loadGroup); + nsCOMPtr baseURL; + sourceDoc->GetBaseURL(*getter_AddRefs(baseURL)); + doc->SetBaseURL(baseURL); + // XXX We might want to call SetDefaultStylesheets here + + // Notify the contentsink that the document is created + nsCOMPtr observer = do_QueryReferent(mObserver); + if (observer) { + observer->OnDocumentCreated(mDocument); + } + + // Create the content + + // When transforming into a non-displayed document (i.e. when there is no + // observer) we only create a transformiix:result root element. + // Don't do this when called through nsIXSLTProcessorObsolete (i.e. when + // aResultDocument is set) for compability reasons + nsCOMPtr textContainer; + if (!aResultDocument && !observer) { + nsCOMPtr docElement; + mDocument->CreateElementNS(NS_LITERAL_STRING(kTXNameSpaceURI), + NS_LITERAL_STRING(kTXWrapper), + getter_AddRefs(docElement)); + NS_ASSERTION(docElement, "Failed to create wrapper element"); + if (!docElement) { + return; + } + + rv = mDocument->AppendChild(docElement, getter_AddRefs(textContainer)); + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to append the wrapper element"); + if (NS_FAILED(rv)) { + return; + } + } + else { + nsCOMPtr element, docElement; + nsCOMPtr parent, pre; + + NS_NAMED_LITERAL_STRING(XHTML_NSURI, "http://www.w3.org/1999/xhtml"); + + mDocument->CreateElementNS(XHTML_NSURI, + NS_LITERAL_STRING("html"), + getter_AddRefs(docElement)); + nsCOMPtr rootContent = do_QueryInterface(docElement); + NS_ASSERTION(rootContent, "Need root element"); + if (!rootContent) { + return; + } + + rv = rootContent->SetDocument(doc, PR_FALSE, PR_TRUE); + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to set the document"); + if (NS_FAILED(rv)) { + return; + } + + rv = doc->SetRootContent(rootContent); + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to set the root content"); + if (NS_FAILED(rv)) { + return; + } + + mDocument->CreateElementNS(XHTML_NSURI, + NS_LITERAL_STRING("head"), + getter_AddRefs(element)); + NS_ASSERTION(element, "Failed to create head element"); + if (!element) { + return; + } + + rv = docElement->AppendChild(element, getter_AddRefs(parent)); + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to append the head element"); + if (NS_FAILED(rv)) { + return; + } + + mDocument->CreateElementNS(XHTML_NSURI, + NS_LITERAL_STRING("body"), + getter_AddRefs(element)); + NS_ASSERTION(element, "Failed to create body element"); + if (!element) { + return; + } + + rv = docElement->AppendChild(element, getter_AddRefs(parent)); + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to append the body element"); + if (NS_FAILED(rv)) { + return; + } + + mDocument->CreateElementNS(XHTML_NSURI, + NS_LITERAL_STRING("pre"), + getter_AddRefs(element)); + NS_ASSERTION(element, "Failed to create pre element"); + if (!element) { + return; + } + + rv = parent->AppendChild(element, getter_AddRefs(pre)); + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to append the pre element"); + if (NS_FAILED(rv)) { + return; + } + + nsCOMPtr htmlElement = do_QueryInterface(pre); + htmlElement->SetId(NS_LITERAL_STRING("transformiixResult")); + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to append the id"); + + textContainer = pre; + } - nsCOMPtr element, docElement; - nsCOMPtr parent, pre; nsCOMPtr textNode; - - NS_NAMED_LITERAL_STRING(XHTML_NSURI, "http://www.w3.org/1999/xhtml"); - - aDocument->CreateElementNS(XHTML_NSURI, - NS_LITERAL_STRING("html"), - getter_AddRefs(docElement)); - mRootContent = do_QueryInterface(docElement); - NS_ASSERTION(mRootContent, "Need root element"); - if (!mRootContent) { - return; - } - - nsCOMPtr document = do_QueryInterface(aDocument); - NS_ASSERTION(document, "Need document"); - - nsresult rv = mRootContent->SetDocument(document, PR_FALSE, PR_TRUE); - NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to set the document"); - if (NS_FAILED(rv)) { - return; - } - - rv = document->SetRootContent(mRootContent); - NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to set the root content"); - if (NS_FAILED(rv)) { - return; - } - - aDocument->CreateElementNS(XHTML_NSURI, - NS_LITERAL_STRING("head"), - getter_AddRefs(element)); - NS_ASSERTION(element, "Failed to create head element"); - if (!element) { - return; - } - - rv = docElement->AppendChild(element, getter_AddRefs(parent)); - NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to append the head element"); - if (NS_FAILED(rv)) { - return; - } - - aDocument->CreateElementNS(XHTML_NSURI, - NS_LITERAL_STRING("body"), - getter_AddRefs(element)); - NS_ASSERTION(element, "Failed to create body element"); - if (!mRootContent) { - return; - } - - rv = docElement->AppendChild(element, getter_AddRefs(parent)); - NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to append the body element"); - if (NS_FAILED(rv)) { - return; - } - - aDocument->CreateElementNS(XHTML_NSURI, - NS_LITERAL_STRING("pre"), - getter_AddRefs(element)); - NS_ASSERTION(element, "Failed to create pre element"); - if (!element) { - return; - } - - rv = parent->AppendChild(element, getter_AddRefs(pre)); - NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to append the pre element"); - if (NS_FAILED(rv)) { - return; - } - - nsCOMPtr htmlElement = do_QueryInterface(pre); - htmlElement->SetId(NS_LITERAL_STRING("transformiixResult")); - NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to append the id"); - - aDocument->CreateTextNode(NS_LITERAL_STRING(""), + mDocument->CreateTextNode(NS_LITERAL_STRING(""), getter_AddRefs(textNode)); NS_ASSERTION(textNode, "Failed to create the text node"); if (!textNode) { return; } - rv = pre->AppendChild(textNode, getter_AddRefs(parent)); + nsCOMPtr dummy; + rv = textContainer->AppendChild(textNode, getter_AddRefs(dummy)); NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to append the text node"); if (NS_FAILED(rv)) { return; @@ -214,18 +315,13 @@ void txMozillaTextOutput::setOutputDocument(nsIDOMDocument* aDocument) mTextNode = textNode; } -void txMozillaTextOutput::setOutputFormat(txOutputFormat* aOutputFormat) -{ - mOutputFormat.reset(); - mOutputFormat.merge(*aOutputFormat); - mOutputFormat.setFromDefaults(); -} - -void txMozillaTextOutput::startDocument() -{ -} - void txMozillaTextOutput::startElement(const String& aName, const PRInt32 aNsID) { } + +void txMozillaTextOutput::getOutputDocument(nsIDOMDocument** aDocument) +{ + *aDocument = mDocument; + NS_IF_ADDREF(*aDocument); +} diff --git a/content/xslt/src/xslt/txMozillaTextOutput.h b/content/xslt/src/xslt/txMozillaTextOutput.h index a582fca36729..81e3e3cfa1e4 100644 --- a/content/xslt/src/xslt/txMozillaTextOutput.h +++ b/content/xslt/src/xslt/txMozillaTextOutput.h @@ -43,14 +43,24 @@ #include "nsIContent.h" #include "nsIDOMCharacterData.h" #include "nsCOMPtr.h" +#include "nsWeakPtr.h" #include "txOutputFormat.h" +#include "nsIDOMDocument.h" +#include "nsIDOMDocumentFragment.h" -class txMozillaTextOutput : public txMozillaXMLEventHandler +class nsITransformObserver; + +class txMozillaTextOutput : public txIOutputXMLEventHandler { public: - txMozillaTextOutput(); + txMozillaTextOutput(nsIDOMDocument* aSourceDocument, + nsIDOMDocument* aResultDocument, + nsITransformObserver* aObserver); + txMozillaTextOutput(nsIDOMDocumentFragment* aDest); virtual ~txMozillaTextOutput(); + NS_DECL_ISUPPORTS + /** * Signals to receive the start of an attribute. * @@ -69,6 +79,16 @@ public: */ void characters(const String& aData); + /** + * Signals to receive characters that don't need output escaping. + * + * @param aData the characters to receive + */ + void charactersNoOutputEscaping(const String& aData) + { + NS_ASSERTION(0, "Don't call this in module, we don't do d-o-e"); + } + /** * Signals to receive data that should be treated as a comment. * @@ -91,6 +111,18 @@ public: void endElement(const String& aName, const PRInt32 aNsID); + /** + * Returns whether the output handler supports + * disable-output-escaping. + * + * @return MB_TRUE if this handler supports + * disable-output-escaping + */ + MBool hasDisableOutputEscaping() + { + return MB_FALSE; + } + /** * Signals to receive a processing instruction. * @@ -114,48 +146,19 @@ public: const PRInt32 aNsID); /** - * Sets the output format. - * - * @param aOutputFormat the output format - */ - void setOutputFormat(txOutputFormat* aOutputFormat); - - /** - * Disables loading of stylesheets. - */ - void disableStylesheetLoad(); - - /** - * Returns the root content of the result. - * - * @param aReturn the root content - */ - nsresult getRootContent(nsIContent** aReturn); - - /** - * Returns PR_TRUE if the event handler has finished anything - * extra that had to happen after the transform has finished. - */ - PRBool isDone(); - - /** - * Removes a script element from the array of elements that are - * still loading. - * - * @param aReturn the script element to remove - */ - void removeScriptElement(nsIDOMHTMLScriptElement *aElement); - - /** - * Sets the Mozilla output document. + * Gets the Mozilla output document * * @param aDocument the Mozilla output document */ - void setOutputDocument(nsIDOMDocument* aDocument); + void getOutputDocument(nsIDOMDocument** aDocument); private: + void createResultDocument(nsIDOMDocument* aSourceDocument, + nsIDOMDocument* aResultDocument); + nsCOMPtr mTextNode; - nsCOMPtr mRootContent; + nsWeakPtr mObserver; + nsCOMPtr mDocument; txOutputFormat mOutputFormat; }; diff --git a/content/xslt/src/xslt/txMozillaXMLOutput.cpp b/content/xslt/src/xslt/txMozillaXMLOutput.cpp index b88919824122..18221cae6c2e 100644 --- a/content/xslt/src/xslt/txMozillaXMLOutput.cpp +++ b/content/xslt/src/xslt/txMozillaXMLOutput.cpp @@ -39,6 +39,7 @@ #include "txMozillaXMLOutput.h" #include "nsIDocument.h" +#include "nsIDocShell.h" #include "nsIDOMComment.h" #include "nsIDOMDocumentType.h" #include "nsIDOMDOMImplementation.h" @@ -48,31 +49,80 @@ #include "nsIDOMHTMLTableSectionElem.h" #include "nsIDOMHTMLScriptElement.h" #include "nsIDOMNSDocument.h" +#include "nsIParser.h" +#include "nsIRefreshURI.h" +#include "nsIScriptGlobalObject.h" +#include "nsITextContent.h" +#include "nsIDocumentTransformer.h" +#include "nsIXMLContent.h" +#include "nsContentCID.h" +#include "nsNetUtil.h" #include "nsUnicharUtils.h" #include "txAtoms.h" -#include "nsIParser.h" -#include "nsNetUtil.h" -#include "nsIScriptGlobalObject.h" -#include "nsIRefreshURI.h" -#include "nsIDocShell.h" +#include "nsIDOMDocumentFragment.h" + +static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID); +static NS_DEFINE_CID(kHTMLDocumentCID, NS_HTMLDOCUMENT_CID); #define kXHTMLNameSpaceURI "http://www.w3.org/1999/xhtml" -#define kTXNameSpaceURI "http://www.mozilla.org/TransforMiix" -#define kTXWrapper "transformiix:result" #define TX_ENSURE_CURRENTNODE \ NS_ASSERTION(mCurrentNode, "mCurrentNode is NULL"); \ if (!mCurrentNode) \ return -txMozillaXMLOutput::txMozillaXMLOutput() : mDisableStylesheetLoad(PR_FALSE) +txMozillaXMLOutput::txMozillaXMLOutput(const String& aRootName, + PRInt32 aRootNsID, + txOutputFormat* aFormat, + nsIDOMDocument* aSourceDocument, + nsIDOMDocument* aResultDocument, + nsITransformObserver* aObserver) + : mStyleSheetCount(0), + mDontAddCurrent(PR_FALSE), + mHaveTitleElement(PR_FALSE), + mHaveBaseElement(PR_FALSE), + mInTransform(PR_FALSE), + mCreatingNewDocument(PR_TRUE) { + NS_INIT_ISUPPORTS(); + mOutputFormat.merge(*aFormat); + mOutputFormat.setFromDefaults(); + + mObserver = do_GetWeakReference(aObserver); + + createResultDocument(aRootName, aRootNsID, aSourceDocument, aResultDocument); +} + +txMozillaXMLOutput::txMozillaXMLOutput(txOutputFormat* aFormat, + nsIDOMDocumentFragment* aFragment) + : mStyleSheetCount(0), + mDontAddCurrent(PR_FALSE), + mHaveTitleElement(PR_FALSE), + mHaveBaseElement(PR_FALSE), + mInTransform(PR_FALSE), + mCreatingNewDocument(PR_FALSE) +{ + NS_INIT_ISUPPORTS(); + mOutputFormat.merge(*aFormat); + mOutputFormat.setFromDefaults(); + + aFragment->GetOwnerDocument(getter_AddRefs(mDocument)); + nsCOMPtr doc = do_QueryInterface(mDocument); + NS_ASSERTION(doc, "can't QI to nsIDocument"); + doc->GetNameSpaceManager(*getter_AddRefs(mNameSpaceManager)); + NS_ASSERTION(mNameSpaceManager, "Can't get namespace manager."); + + mCurrentNode = aFragment; } txMozillaXMLOutput::~txMozillaXMLOutput() { } +NS_IMPL_ISUPPORTS2(txMozillaXMLOutput, + txIOutputXMLEventHandler, + nsIScriptLoaderObserver); + void txMozillaXMLOutput::attribute(const String& aName, const PRInt32 aNsID, const String& aValue) @@ -118,22 +168,16 @@ void txMozillaXMLOutput::comment(const String& aData) nsresult rv = mDocument->CreateComment(aData, getter_AddRefs(comment)); NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create comment"); - - nsCOMPtr node = do_QueryInterface(comment); nsCOMPtr resultNode; - rv = mCurrentNode->AppendChild(node, getter_AddRefs(resultNode)); + rv = mCurrentNode->AppendChild(comment, getter_AddRefs(resultNode)); NS_ASSERTION(NS_SUCCEEDED(rv), "Can't append comment"); } -void txMozillaXMLOutput::disableStylesheetLoad() -{ - mDisableStylesheetLoad = PR_TRUE; -} - void txMozillaXMLOutput::endDocument() { closePrevious(eCloseElement | eFlushText); - if (!mHaveTitleElement) { + // This should really be handled by nsIDocument::Reset + if (mCreatingNewDocument && !mHaveTitleElement) { nsCOMPtr domDoc = do_QueryInterface(mDocument); if (domDoc) { domDoc->SetTitle(NS_LITERAL_STRING("")); @@ -155,10 +199,15 @@ void txMozillaXMLOutput::endDocument() } } } + + mInTransform = PR_FALSE; + SignalTransformEnd(); } void txMozillaXMLOutput::endElement(const String& aName, const PRInt32 aNsID) { + TX_ENSURE_CURRENTNODE; + #ifdef DEBUG nsAutoString nodeName; mCurrentNode->GetNodeName(nodeName); @@ -204,21 +253,10 @@ void txMozillaXMLOutput::endElement(const String& aName, const PRInt32 aNsID) } } -nsresult txMozillaXMLOutput::getRootContent(nsIContent** aReturn) +void txMozillaXMLOutput::getOutputDocument(nsIDOMDocument** aDocument) { - NS_ASSERTION(aReturn, "NULL pointer passed to getRootContent"); - - *aReturn = mRootContent; - NS_IF_ADDREF(*aReturn); - return NS_OK; -} - -PRBool txMozillaXMLOutput::isDone() -{ - PRUint32 scriptCount = 0; - if (mScriptElements) - mScriptElements->Count(&scriptCount); - return (scriptCount == 0); + *aDocument = mDocument; + NS_IF_ADDREF(*aDocument); } void txMozillaXMLOutput::processingInstruction(const String& aTarget, const String& aData) @@ -234,24 +272,30 @@ void txMozillaXMLOutput::processingInstruction(const String& aTarget, const Stri nsresult rv = mDocument->CreateProcessingInstruction(aTarget, aData, getter_AddRefs(pi)); NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create processing instruction"); + if (NS_FAILED(rv)) + return; - nsCOMPtr ssle = do_QueryInterface(pi); - if (ssle) { - ssle->InitStyleLinkElement(nsnull, PR_FALSE); - ssle->SetEnableUpdates(PR_FALSE); + nsCOMPtr ssle; + if (mCreatingNewDocument) { + ssle = do_QueryInterface(pi); + if (ssle) { + ssle->InitStyleLinkElement(nsnull, PR_FALSE); + ssle->SetEnableUpdates(PR_FALSE); + } } nsCOMPtr resultNode; - mCurrentNode->AppendChild(pi, getter_AddRefs(resultNode)); + rv = mCurrentNode->AppendChild(pi, getter_AddRefs(resultNode)); NS_ASSERTION(NS_SUCCEEDED(rv), "Can't append processing instruction"); if (NS_FAILED(rv)) return; if (ssle) { - ssle->SetEnableUpdates(PR_TRUE); - rv = ssle->UpdateStyleSheet(nsnull, mStyleSheetCount); - if (NS_SUCCEEDED(rv) || (rv == NS_ERROR_HTMLPARSER_BLOCK)) - mStyleSheetCount++; + ssle->SetEnableUpdates(PR_TRUE); + rv = ssle->UpdateStyleSheet(nsnull, mStyleSheetCount); + if (NS_SUCCEEDED(rv) || (rv == NS_ERROR_HTMLPARSER_BLOCK)) { + mStyleSheetCount++; + } } } @@ -264,102 +308,54 @@ void txMozillaXMLOutput::removeScriptElement(nsIDOMHTMLScriptElement *aElement) } } -void txMozillaXMLOutput::setOutputDocument(nsIDOMDocument* aDocument) -{ - NS_ASSERTION(aDocument, "Document can't be NULL!"); - if (!aDocument) - return; - - mDocument = aDocument; - mCurrentNode = mDocument; - mStyleSheetCount = 0; - mHaveTitleElement = PR_FALSE; - mHaveBaseElement = PR_FALSE; - mNonAddedParent = nsnull; - mNonAddedNode = nsnull; - mRefreshString.Truncate(); - - nsCOMPtr doc = do_QueryInterface(aDocument); - doc->GetNameSpaceManager(*getter_AddRefs(mNameSpaceManager)); - NS_ASSERTION(mNameSpaceManager, "Can't get namespace manager."); -} - -void txMozillaXMLOutput::setOutputFormat(txOutputFormat* aOutputFormat) -{ - mOutputFormat.reset(); - mOutputFormat.merge(*aOutputFormat); - mOutputFormat.setFromDefaults(); -} - void txMozillaXMLOutput::startDocument() { - NS_ASSERTION(mDocument, "Document can't be NULL!"); + mInTransform = PR_TRUE; } void txMozillaXMLOutput::startElement(const String& aName, const PRInt32 aNsID) { + TX_ENSURE_CURRENTNODE; + closePrevious(eCloseElement | eFlushText); nsresult rv; - if (!mRootContent && !mOutputFormat.mSystemId.isEmpty()) { - // No root element yet, so add the doctype if necesary. - nsCOMPtr implementation; - rv = mDocument->GetImplementation(getter_AddRefs(implementation)); - NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get DOMImplementation"); - if (NS_SUCCEEDED(rv)) { - nsAutoString qName; - nsCOMPtr documentType; - nsCOMPtr firstNode, node; - if (mOutputFormat.mMethod == eHTMLOutput) - qName.Assign(NS_LITERAL_STRING("html")); - else - qName.Assign(aName); - rv = implementation->CreateDocumentType(qName, - mOutputFormat.mPublicId, - mOutputFormat.mSystemId, - getter_AddRefs(documentType)); - NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create doctype"); - - mDocument->GetFirstChild(getter_AddRefs(firstNode)); - rv = mDocument->InsertBefore(documentType, firstNode, getter_AddRefs(node)); - NS_ASSERTION(NS_SUCCEEDED(rv), "Can't insert doctype"); - } - } - nsCOMPtr element; mDontAddCurrent = PR_FALSE; if ((mOutputFormat.mMethod == eHTMLOutput) && (aNsID == kNameSpaceID_None)) { - // Outputting HTML as XHTML, lowercase element names - nsAutoString lowerName(aName); - ToLowerCase(lowerName); - rv = mDocument->CreateElementNS(NS_LITERAL_STRING(kXHTMLNameSpaceURI), lowerName, - getter_AddRefs(element)); - NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create element"); + rv = mDocument->CreateElement(aName, + getter_AddRefs(element)); + if (NS_FAILED(rv)) { + return; + } startHTMLElement(element); } else { nsAutoString nsURI; mNameSpaceManager->GetNameSpaceURI(aNsID, nsURI); - rv = mDocument->CreateElementNS(nsURI, aName, getter_AddRefs(element)); + rv = mDocument->CreateElementNS(nsURI, aName, + getter_AddRefs(element)); NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create element"); + if (NS_FAILED(rv)) { + return; + } if (aNsID == kNameSpaceID_XHTML) startHTMLElement(element); } - if (element) { + if (mCreatingNewDocument) { nsCOMPtr cont = do_QueryInterface(element); - if (cont) { - nsCOMPtr doc = do_QueryInterface(mDocument); - cont->SetDocument(doc, PR_FALSE, PR_TRUE); - } - mParentNode = mCurrentNode; - mCurrentNode = do_QueryInterface(element); + NS_ASSERTION(cont, "element doesn't implement nsIContent"); + nsCOMPtr doc = do_QueryInterface(mDocument); + cont->SetDocument(doc, PR_FALSE, PR_TRUE); } + mParentNode = mCurrentNode; + mCurrentNode = do_QueryInterface(element); } void txMozillaXMLOutput::closePrevious(PRInt8 aAction) @@ -367,11 +363,6 @@ void txMozillaXMLOutput::closePrevious(PRInt8 aAction) TX_ENSURE_CURRENTNODE; nsresult rv; - PRInt32 namespaceID = kNameSpaceID_None; - nsCOMPtr currentContent = do_QueryInterface(mCurrentNode); - if (currentContent) - currentContent->GetNameSpaceID(namespaceID); - if ((aAction & eCloseElement) && mParentNode) { nsCOMPtr document = do_QueryInterface(mParentNode); nsCOMPtr currentElement = do_QueryInterface(mCurrentNode); @@ -446,16 +437,18 @@ void txMozillaXMLOutput::startHTMLElement(nsIDOMElement* aElement) mDontAddCurrent = (atom == txHTMLAtoms::script); - nsCOMPtr ssle = - do_QueryInterface(aElement); - if (ssle) { - // XXX Trick nsCSSLoader into blocking/notifying us? - // We would need to implement nsIParser and - // pass ourselves as first parameter to - // InitStyleLinkElement. We would then be notified - // of stylesheet loads/load failures. - ssle->InitStyleLinkElement(nsnull, PR_FALSE); - ssle->SetEnableUpdates(PR_FALSE); + if (mCreatingNewDocument) { + nsCOMPtr ssle = + do_QueryInterface(aElement); + if (ssle) { + // XXX Trick nsCSSLoader into blocking/notifying us? + // We would need to implement nsIParser and + // pass ourselves as first parameter to + // InitStyleLinkElement. We would then be notified + // of stylesheet loads/load failures. + ssle->InitStyleLinkElement(nsnull, PR_FALSE); + ssle->SetEnableUpdates(PR_FALSE); + } } } @@ -503,7 +496,8 @@ void txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement, } } // Load scripts - else if (atom == txHTMLAtoms::script) { + else if (mCreatingNewDocument && + atom == txHTMLAtoms::script) { // Add this script element to the array of loading script elements. nsCOMPtr scriptElement = do_QueryInterface(mCurrentNode); @@ -515,7 +509,8 @@ void txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement, mScriptElements->AppendElement(scriptElement); } // Set document title - else if (atom == txHTMLAtoms::title && !mHaveTitleElement) { + else if (mCreatingNewDocument && + atom == txHTMLAtoms::title && !mHaveTitleElement) { // The first title wins mHaveTitleElement = PR_TRUE; nsCOMPtr domDoc = do_QueryInterface(mDocument); @@ -528,7 +523,8 @@ void txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement, domDoc->SetTitle(text); } } - else if (atom == txHTMLAtoms::base && !mHaveBaseElement) { + else if (mCreatingNewDocument && + atom == txHTMLAtoms::base && !mHaveBaseElement) { // The first base wins mHaveBaseElement = PR_TRUE; @@ -545,7 +541,8 @@ void txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement, return; doc->SetBaseURL(baseURI); // The document checks if it is legal to set this base } - else if (atom == txHTMLAtoms::meta) { + else if (mCreatingNewDocument && + atom == txHTMLAtoms::meta) { // handle HTTP-EQUIV data nsAutoString httpEquiv; content->GetAttr(kNameSpaceID_None, txHTMLAtoms::httpEquiv, httpEquiv); @@ -563,7 +560,7 @@ void txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement, } // Handle all sorts of stylesheets - if (!mDisableStylesheetLoad) { + if (mCreatingNewDocument) { nsCOMPtr ssle = do_QueryInterface(aElement); if (ssle) { @@ -603,3 +600,168 @@ void txMozillaXMLOutput::wrapChildren(nsIDOMNode* aCurrentNode, } } } + +nsresult +txMozillaXMLOutput::createResultDocument(const String& aName, PRInt32 aNsID, + nsIDOMDocument* aSourceDocument, + nsIDOMDocument* aResultDocument) +{ + nsresult rv; + + nsCOMPtr doc; + if (!aResultDocument) { + // Create the document + if (mOutputFormat.mMethod == eHTMLOutput) { + doc = do_CreateInstance(kHTMLDocumentCID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + // We should check the root name/namespace here and create the + // appropriate document + doc = do_CreateInstance(kXMLDocumentCID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + } + mDocument = do_QueryInterface(doc); + } + else { + mDocument = aResultDocument; + doc = do_QueryInterface(aResultDocument); + } + mCurrentNode = mDocument; + doc->GetNameSpaceManager(*getter_AddRefs(mNameSpaceManager)); + NS_ASSERTION(mNameSpaceManager, "Can't get namespace manager."); + + // Reset and set up the document + nsCOMPtr loadGroup; + nsCOMPtr channel; + nsCOMPtr sourceDoc = do_QueryInterface(aSourceDocument); + sourceDoc->GetDocumentLoadGroup(getter_AddRefs(loadGroup)); + nsCOMPtr serv = do_GetService(NS_IOSERVICE_CONTRACTID); + if (serv) { + // Create a temporary channel to get nsIDocument->Reset to + // do the right thing. We want the output document to get + // much of the input document's characteristics. + nsCOMPtr docURL; + sourceDoc->GetDocumentURL(getter_AddRefs(docURL)); + serv->NewChannelFromURI(docURL, getter_AddRefs(channel)); + } + doc->Reset(channel, loadGroup); + nsCOMPtr baseURL; + sourceDoc->GetBaseURL(*getter_AddRefs(baseURL)); + doc->SetBaseURL(baseURL); + // XXX We might want to call SetDefaultStylesheets here + + // Set up script loader of the result document. + nsCOMPtr loader; + doc->GetScriptLoader(getter_AddRefs(loader)); + nsCOMPtr observer = do_QueryReferent(mObserver); + if (loader) { + if (observer) { + loader->AddObserver(this); + } + else { + // Don't load scripts, we can't notify the caller when they're loaded. + loader->SetEnabled(PR_FALSE); + } + } + + // Notify the contentsink that the document is created + if (observer) { + observer->OnDocumentCreated(mDocument); + } + + // Add a doc-type if requested + if (!mOutputFormat.mSystemId.isEmpty()) { + nsCOMPtr implementation; + rv = aSourceDocument->GetImplementation(getter_AddRefs(implementation)); + NS_ENSURE_SUCCESS(rv, rv); + nsAutoString qName; + if (mOutputFormat.mMethod == eHTMLOutput) { + qName.Assign(NS_LITERAL_STRING("html")); + } + else { + qName.Assign(aName.getConstNSString()); + } + nsCOMPtr documentType; + rv = implementation->CreateDocumentType(qName, + mOutputFormat.mPublicId, + mOutputFormat.mSystemId, + getter_AddRefs(documentType)); + NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create doctype"); + nsCOMPtr tmp; + mDocument->AppendChild(documentType, getter_AddRefs(tmp)); + } + + return NS_OK; +} + +NS_IMETHODIMP +txMozillaXMLOutput::ScriptAvailable(nsresult aResult, + nsIDOMHTMLScriptElement *aElement, + PRBool aIsInline, + PRBool aWasPending, + nsIURI *aURI, + PRInt32 aLineNo, + const nsAString& aScript) +{ + if (NS_FAILED(aResult)) { + removeScriptElement(aElement); + SignalTransformEnd(); + } + + return NS_OK; +} + +NS_IMETHODIMP +txMozillaXMLOutput::ScriptEvaluated(nsresult aResult, + nsIDOMHTMLScriptElement *aElement, + PRBool aIsInline, + PRBool aWasPending) +{ + removeScriptElement(aElement); + SignalTransformEnd(); + return NS_OK; +} + +void +txMozillaXMLOutput::SignalTransformEnd() +{ + if (mInTransform) { + return; + } + + nsCOMPtr observer = do_QueryReferent(mObserver); + if (!observer) { + return; + } + + if (mScriptElements) { + PRUint32 scriptCount = 0; + mScriptElements->Count(&scriptCount); + if (scriptCount != 0) { + return; + } + } + + // Make sure that we don't get deleted while this function is executed and + // we remove ourselfs from the scriptloader + nsCOMPtr kungFuDeathGrip(this); + + mObserver = nsnull; + + // XXX Need a better way to determine transform success/failure + if (mDocument) { + nsCOMPtr loader; + nsCOMPtr doc = do_QueryInterface(mDocument); + doc->GetScriptLoader(getter_AddRefs(loader)); + if (loader) { + loader->RemoveObserver(this); + } + + observer->OnTransformDone(NS_OK, mDocument); + } + else { + // XXX Need better error message and code. + observer->OnTransformDone(NS_ERROR_FAILURE, nsnull); + } +} diff --git a/content/xslt/src/xslt/txMozillaXMLOutput.h b/content/xslt/src/xslt/txMozillaXMLOutput.h index 2d5884fd1256..fcd23859329d 100644 --- a/content/xslt/src/xslt/txMozillaXMLOutput.h +++ b/content/xslt/src/xslt/txMozillaXMLOutput.h @@ -44,17 +44,31 @@ #include "nsIDOMDocument.h" #include "nsIDOMHTMLTextAreaElement.h" #include "nsINameSpaceManager.h" +#include "nsIScriptLoader.h" +#include "nsIScriptLoaderObserver.h" #include "nsIStyleSheetLinkingElement.h" #include "nsString.h" #include "nsSupportsArray.h" +#include "nsWeakPtr.h" #include "txOutputFormat.h" -class txMozillaXMLOutput : public txMozillaXMLEventHandler +class txMozillaXMLOutput : public txIOutputXMLEventHandler, + public nsIScriptLoaderObserver { public: - txMozillaXMLOutput(); + txMozillaXMLOutput(const String& aRootName, + PRInt32 aRootNsID, + txOutputFormat* aFormat, + nsIDOMDocument* aSourceDocument, + nsIDOMDocument* aResultDocument, + nsITransformObserver* aObserver); + txMozillaXMLOutput(txOutputFormat* aFormat, + nsIDOMDocumentFragment* aFragment); virtual ~txMozillaXMLOutput(); + NS_DECL_ISUPPORTS + NS_DECL_NSISCRIPTLOADEROBSERVER + /** * Signals to receive the start of an attribute. * @@ -73,6 +87,16 @@ public: */ void characters(const String& aData); + /** + * Signals to receive characters that don't need output escaping. + * + * @param aData the characters to receive + */ + void charactersNoOutputEscaping(const String& aData) + { + NS_ASSERTION(0, "Don't call this in module, we don't do d-o-e"); + } + /** * Signals to receive data that should be treated as a comment. * @@ -95,6 +119,18 @@ public: void endElement(const String& aName, const PRInt32 aNsID); + /** + * Returns whether the output handler supports + * disable-output-escaping. + * + * @return MB_TRUE if this handler supports + * disable-output-escaping + */ + MBool hasDisableOutputEscaping() + { + return MB_FALSE; + } + /** * Signals to receive a processing instruction. * @@ -118,31 +154,6 @@ public: void startElement(const String& aName, const PRInt32 aNsID); - /** - * Sets the output format. - * - * @param aOutputFormat the output format - */ - void setOutputFormat(txOutputFormat* aOutputFormat); - - /** - * Disables loading of stylesheets. - */ - void disableStylesheetLoad(); - - /** - * Returns the root content of the result. - * - * @param aReturn the root content - */ - nsresult getRootContent(nsIContent** aReturn); - - /** - * Returns PR_TRUE if the event handler has finished anything - * extra that had to happen after the transform has finished. - */ - PRBool isDone(); - /** * Removes a script element from the array of elements that are * still loading. @@ -152,11 +163,11 @@ public: void removeScriptElement(nsIDOMHTMLScriptElement *aElement); /** - * Sets the Mozilla output document. + * Gets the Mozilla output document * * @param aDocument the Mozilla output document */ - void setOutputDocument(nsIDOMDocument* aDocument); + void getOutputDocument(nsIDOMDocument** aDocument); private: void closePrevious(PRInt8 aAction); @@ -164,11 +175,16 @@ private: void endHTMLElement(nsIDOMElement* aElement, PRBool aXHTML); void processHTTPEquiv(nsIAtom* aHeader, const nsAString& aValue); void wrapChildren(nsIDOMNode* aCurrentNode, nsIDOMElement* aWrapper); + nsresult createResultDocument(const String& aName, PRInt32 aNsID, + nsIDOMDocument* aSourceDocument, + nsIDOMDocument* aResultDocument); + void SignalTransformEnd(); nsCOMPtr mDocument; nsCOMPtr mCurrentNode; nsCOMPtr mParentNode; nsCOMPtr mRootContent; + nsWeakPtr mObserver; nsCOMPtr mNonAddedParent; nsCOMPtr mNonAddedNode; @@ -184,12 +200,14 @@ private: txOutputFormat mOutputFormat; - PRPackedBool mDisableStylesheetLoad; PRPackedBool mDontAddCurrent; PRPackedBool mHaveTitleElement; PRPackedBool mHaveBaseElement; + PRPackedBool mInTransform; + PRPackedBool mCreatingNewDocument; + enum txAction { eCloseElement = 1, eFlushText = 2 }; }; diff --git a/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp b/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp new file mode 100644 index 000000000000..1f7149c7acd8 --- /dev/null +++ b/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp @@ -0,0 +1,768 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Van der Beken (original author) + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "txMozillaXSLTProcessor.h" +#include "nsContentCID.h" +#include "nsDOMError.h" +#include "nsIContent.h" +#include "nsIDocument.h" +#include "nsIDOMClassInfo.h" +#include "nsIScriptLoader.h" +#include "nsNetUtil.h" +#include "ProcessorState.h" +#include "txMozillaTextOutput.h" +#include "txMozillaXMLOutput.h" +#include "txSingleNodeContext.h" +#include "txURIUtils.h" +#include "XMLUtils.h" +#include "txUnknownHandler.h" +#include "nsIHTMLDocument.h" + +/** + * Output Handler Factories + */ +class txToDocHandlerFactory : public txIOutputHandlerFactory +{ +public: + txToDocHandlerFactory(ProcessorState* aPs, + nsIDOMDocument* aSourceDocument, + nsIDOMDocument* aResultDocument, + nsITransformObserver* aObserver) + : mPs(aPs), mSourceDocument(aSourceDocument), + mResultDocument(aResultDocument), mObserver(aObserver) + { + } + + virtual ~txToDocHandlerFactory() + { + } + + TX_DECL_TXIOUTPUTHANDLERFACTORY; + +private: + ProcessorState* mPs; + nsCOMPtr mSourceDocument; + nsCOMPtr mResultDocument; + nsCOMPtr mObserver; +}; + +class txToFragmentHandlerFactory : public txIOutputHandlerFactory +{ +public: + txToFragmentHandlerFactory(nsIDOMDocumentFragment* aFragment) + : mFragment(aFragment) + { + } + + virtual ~txToFragmentHandlerFactory() + { + } + + TX_DECL_TXIOUTPUTHANDLERFACTORY; + +private: + nsCOMPtr mFragment; +}; + +nsresult +txToDocHandlerFactory::createHandlerWith(txOutputFormat* aFormat, + txIOutputXMLEventHandler** aHandler) +{ + *aHandler = nsnull; + switch (aFormat->mMethod) { + case eMethodNotSet: + case eXMLOutput: + { + *aHandler = new txUnknownHandler(mPs); + break; + } + + case eHTMLOutput: + { + *aHandler = new txMozillaXMLOutput(String(), kNameSpaceID_None, + aFormat, mSourceDocument, + mResultDocument, mObserver); + break; + } + + case eTextOutput: + { + *aHandler = new txMozillaTextOutput(mSourceDocument, + mResultDocument, + mObserver); + break; + } + } + NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY); + return NS_OK; +} + +nsresult +txToDocHandlerFactory::createHandlerWith(txOutputFormat* aFormat, + const String& aName, + PRInt32 aNsID, + txIOutputXMLEventHandler** aHandler) +{ + *aHandler = nsnull; + switch (aFormat->mMethod) { + case eMethodNotSet: + { + NS_ERROR("How can method not be known when root element is?"); + return NS_ERROR_UNEXPECTED; + } + + case eXMLOutput: + case eHTMLOutput: + { + *aHandler = new txMozillaXMLOutput(aName, aNsID, aFormat, + mSourceDocument, + mResultDocument, + mObserver); + break; + } + + case eTextOutput: + { + *aHandler = new txMozillaTextOutput(mSourceDocument, + mResultDocument, + mObserver); + break; + } + } + NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY); + return NS_OK; +} + +nsresult +txToFragmentHandlerFactory::createHandlerWith(txOutputFormat* aFormat, + txIOutputXMLEventHandler** aHandler) +{ + *aHandler = nsnull; + switch (aFormat->mMethod) { + case eMethodNotSet: + { + txOutputFormat format; + format.merge(*aFormat); + nsCOMPtr doc; + mFragment->GetOwnerDocument(getter_AddRefs(doc)); + NS_ASSERTION(doc, "unable to get ownerdocument"); + // Need a way for testing xhtml vs. html. But this is the best + // we can do for now. + nsCOMPtr htmldoc = do_QueryInterface(doc); + format.mMethod = htmldoc ? eHTMLOutput : eXMLOutput; + *aHandler = new txMozillaXMLOutput(&format, mFragment); + break; + } + + case eXMLOutput: + case eHTMLOutput: + { + *aHandler = new txMozillaXMLOutput(aFormat, mFragment); + break; + } + + case eTextOutput: + { + *aHandler = new txMozillaTextOutput(mFragment); + break; + } + } + NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY); + return NS_OK; +} + +nsresult +txToFragmentHandlerFactory::createHandlerWith(txOutputFormat* aFormat, + const String& aName, + PRInt32 aNsID, + txIOutputXMLEventHandler** aHandler) +{ + *aHandler = nsnull; + NS_ASSERTION(aFormat->mMethod != eMethodNotSet, + "How can method not be known when root element is?"); + NS_ENSURE_TRUE(aFormat->mMethod != eMethodNotSet, NS_ERROR_UNEXPECTED); + return createHandlerWith(aFormat, aHandler); +} + +/** + * txMozillaXSLTProcessor + */ + +NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID); + +NS_IMPL_ADDREF(txMozillaXSLTProcessor) +NS_IMPL_RELEASE(txMozillaXSLTProcessor) +NS_INTERFACE_MAP_BEGIN(txMozillaXSLTProcessor) + NS_INTERFACE_MAP_ENTRY(nsIXSLTProcessor) + NS_INTERFACE_MAP_ENTRY(nsIXSLTProcessorObsolete) + NS_INTERFACE_MAP_ENTRY(nsIDocumentTransformer) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXSLTProcessor) + NS_INTERFACE_MAP_ENTRY_EXTERNAL_DOM_CLASSINFO(XSLTProcessor) +NS_INTERFACE_MAP_END + +txMozillaXSLTProcessor::txMozillaXSLTProcessor() : mVariables(PR_TRUE) +{ + NS_INIT_ISUPPORTS(); +} + +txMozillaXSLTProcessor::~txMozillaXSLTProcessor() +{ +} + +NS_IMETHODIMP +txMozillaXSLTProcessor::TransformDocument(nsIDOMNode* aSourceDOM, + nsIDOMNode* aStyleDOM, + nsIDOMDocument* aOutputDoc, + nsISupports* aObserver) +{ + NS_ENSURE_ARG(aSourceDOM); + NS_ENSURE_ARG(aStyleDOM); + NS_ENSURE_ARG(aOutputDoc); + NS_ENSURE_FALSE(aObserver, NS_ERROR_NOT_IMPLEMENTED); + + if (!URIUtils::CanCallerAccess(aSourceDOM) || + !URIUtils::CanCallerAccess(aStyleDOM) || + !URIUtils::CanCallerAccess(aOutputDoc)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + // Create wrapper for the source document. + nsCOMPtr sourceDOMDocument; + aSourceDOM->GetOwnerDocument(getter_AddRefs(sourceDOMDocument)); + if (!sourceDOMDocument) { + sourceDOMDocument = do_QueryInterface(aSourceDOM); + NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE); + } + Document sourceDocument(sourceDOMDocument); + Node* sourceNode = sourceDocument.createWrapper(aSourceDOM); + NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE); + + // Create wrapper for the style document. + nsCOMPtr styleDOMDocument; + aStyleDOM->GetOwnerDocument(getter_AddRefs(styleDOMDocument)); + if (!styleDOMDocument) { + styleDOMDocument = do_QueryInterface(aStyleDOM); + } + Document xslDocument(styleDOMDocument); + + // Create a new ProcessorState. Must be done after creating the documents + // so that C++ will ensure that it is destroyed before the documents. + ProcessorState ps(&sourceDocument, &xslDocument); + + // XXX Need to add error observers + + // Set current txIEvalContext + txSingleNodeContext evalContext(&sourceDocument, &ps); + ps.setEvalContext(&evalContext); + + // Index templates and process top level xslt elements + nsCOMPtr styleDoc = do_QueryInterface(aStyleDOM); + nsresult rv; + if (styleDoc) { + rv = txXSLTProcessor::processStylesheet(&xslDocument, + &mVariables, &ps); + } + else { + nsCOMPtr styleElem = do_QueryInterface(aStyleDOM); + NS_ENSURE_TRUE(styleElem, NS_ERROR_FAILURE); + Element* element = xslDocument.createElement(styleElem); + NS_ENSURE_TRUE(element, NS_ERROR_OUT_OF_MEMORY); + rv = txXSLTProcessor::processTopLevel(element, &mVariables, + &ps); + } + NS_ENSURE_SUCCESS(rv, rv); + + txToDocHandlerFactory handlerFactory(&ps, sourceDOMDocument, aOutputDoc, + nsnull); + ps.mOutputHandlerFactory = &handlerFactory; + + // Process root of XML source document + txXSLTProcessor::transform(&ps); + + return NS_OK; +} + +NS_IMETHODIMP +txMozillaXSLTProcessor::TransformDocument(nsIDOMNode* aSourceDOM, + nsIDOMNode* aStyleDOM, + nsITransformObserver* aObserver, + nsIDOMDocument** aOutputDoc) +{ + NS_ENSURE_ARG(aSourceDOM); + NS_ENSURE_ARG(aStyleDOM); + NS_ASSERTION(aObserver, "no observer"); + NS_ENSURE_ARG_POINTER(aOutputDoc); + + // Create wrapper for the source document. + nsCOMPtr sourceDOMDocument; + aSourceDOM->GetOwnerDocument(getter_AddRefs(sourceDOMDocument)); + if (!sourceDOMDocument) { + sourceDOMDocument = do_QueryInterface(aSourceDOM); + } + NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE); + Document sourceDocument(sourceDOMDocument); + Node* sourceNode = sourceDocument.createWrapper(aSourceDOM); + NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE); + + // Create wrapper for the style document. + nsCOMPtr styleDOMDocument; + aStyleDOM->GetOwnerDocument(getter_AddRefs(styleDOMDocument)); + if (!styleDOMDocument) { + styleDOMDocument = do_QueryInterface(aStyleDOM); + } + Document xslDocument(styleDOMDocument); + + // Create a new ProcessorState. Must be done after creating the documents + // so that C++ will ensure that it is destroyed before the documents. + ProcessorState ps(&sourceDocument, &xslDocument); + + // XXX Need to add error observers + + // Set current txIEvalContext + txSingleNodeContext evalContext(&sourceDocument, &ps); + ps.setEvalContext(&evalContext); + + // Index templates and process top level xslt elements + nsCOMPtr styleDoc = do_QueryInterface(aStyleDOM); + nsresult rv; + if (styleDoc) { + rv = txXSLTProcessor::processStylesheet(&xslDocument, + &mVariables, &ps); + } + else { + nsCOMPtr styleElem = do_QueryInterface(aStyleDOM); + NS_ENSURE_TRUE(styleElem, NS_ERROR_FAILURE); + Element* element = xslDocument.createElement(styleElem); + NS_ENSURE_TRUE(element, NS_ERROR_OUT_OF_MEMORY); + rv = txXSLTProcessor::processTopLevel(element, &mVariables, + &ps); + } + NS_ENSURE_SUCCESS(rv, rv); + + txToDocHandlerFactory handlerFactory(&ps, sourceDOMDocument, nsnull, + aObserver); + ps.mOutputHandlerFactory = &handlerFactory; + + // Process root of XML source document + txXSLTProcessor::transform(&ps); + + ps.mOutputHandler->getOutputDocument(aOutputDoc); + + return NS_OK; +} + +NS_IMETHODIMP +txMozillaXSLTProcessor::ImportStylesheet(nsIDOMNode *aStyle) +{ + if (!URIUtils::CanCallerAccess(aStyle)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + if (mStylesheet) { + return NS_ERROR_NOT_IMPLEMENTED; + } + + PRUint16 type = 0; + aStyle->GetNodeType(&type); + NS_ENSURE_TRUE(type == nsIDOMNode::ELEMENT_NODE || + type == nsIDOMNode::DOCUMENT_NODE, + NS_ERROR_INVALID_ARG); + + mStylesheet = aStyle; + return NS_OK; +} + +NS_IMETHODIMP +txMozillaXSLTProcessor::TransformToDocument(nsIDOMNode *aSource, + nsIDOMDocument **aResult) +{ + NS_ENSURE_ARG(aSource); + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_TRUE(mStylesheet, NS_ERROR_NOT_INITIALIZED); + + if (!URIUtils::CanCallerAccess(aSource)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + // Create wrapper for the source document. + nsCOMPtr sourceDOMDocument; + aSource->GetOwnerDocument(getter_AddRefs(sourceDOMDocument)); + if (!sourceDOMDocument) { + sourceDOMDocument = do_QueryInterface(aSource); + } + NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE); + Document sourceDocument(sourceDOMDocument); + Node* sourceNode = sourceDocument.createWrapper(aSource); + NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE); + + // Create wrapper for the style document. + nsCOMPtr styleDOMDocument; + mStylesheet->GetOwnerDocument(getter_AddRefs(styleDOMDocument)); + if (!styleDOMDocument) { + styleDOMDocument = do_QueryInterface(mStylesheet); + } + Document xslDocument(styleDOMDocument); + + // Create a new ProcessorState. Must be done after creating the documents + // so that C++ will ensure that it is destroyed before the documents. + ProcessorState ps(&sourceDocument, &xslDocument); + + // XXX Need to add error observers + + // Set current txIEvalContext + txSingleNodeContext evalContext(&sourceDocument, &ps); + ps.setEvalContext(&evalContext); + + // Index templates and process top level xslt elements + nsCOMPtr styleDoc = do_QueryInterface(mStylesheet); + nsresult rv; + if (styleDoc) { + rv = txXSLTProcessor::processStylesheet(&xslDocument, + &mVariables, &ps); + } + else { + nsCOMPtr styleElem = do_QueryInterface(mStylesheet); + NS_ENSURE_TRUE(styleElem, NS_ERROR_FAILURE); + Element* element = xslDocument.createElement(styleElem); + NS_ENSURE_TRUE(element, NS_ERROR_OUT_OF_MEMORY); + rv = txXSLTProcessor::processTopLevel(element, &mVariables, + &ps); + } + NS_ENSURE_SUCCESS(rv, rv); + + txToDocHandlerFactory handlerFactory(&ps, sourceDOMDocument, nsnull, + nsnull); + ps.mOutputHandlerFactory = &handlerFactory; + + // Process root of XML source document + txXSLTProcessor::transform(&ps); + + ps.mOutputHandler->getOutputDocument(aResult); + + return NS_OK; +} + +NS_IMETHODIMP +txMozillaXSLTProcessor::TransformToFragment(nsIDOMNode *aSource, + nsIDOMDocument *aOutput, + nsIDOMDocumentFragment **aResult) +{ + NS_ENSURE_ARG(aSource); + NS_ENSURE_ARG(aOutput); + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_TRUE(mStylesheet, NS_ERROR_NOT_INITIALIZED); + + if (!URIUtils::CanCallerAccess(aSource) || + !URIUtils::CanCallerAccess(aOutput)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + // Create wrapper for the source document. + nsCOMPtr sourceDOMDocument; + aSource->GetOwnerDocument(getter_AddRefs(sourceDOMDocument)); + if (!sourceDOMDocument) { + sourceDOMDocument = do_QueryInterface(aSource); + } + NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE); + Document sourceDocument(sourceDOMDocument); + Node* sourceNode = sourceDocument.createWrapper(aSource); + NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE); + + // Create wrapper for the style document. + nsCOMPtr styleDOMDocument; + mStylesheet->GetOwnerDocument(getter_AddRefs(styleDOMDocument)); + if (!styleDOMDocument) { + styleDOMDocument = do_QueryInterface(mStylesheet); + } + Document xslDocument(styleDOMDocument); + + // Create a new ProcessorState. Must be done after creating the documents + // so that C++ will ensure that it is destroyed before the documents. + ProcessorState ps(&sourceDocument, &xslDocument); + + // XXX Need to add error observers + + // Set current txIEvalContext + txSingleNodeContext evalContext(&sourceDocument, &ps); + ps.setEvalContext(&evalContext); + + // Index templates and process top level xslt elements + nsCOMPtr styleDoc = do_QueryInterface(mStylesheet); + nsresult rv; + if (styleDoc) { + rv = txXSLTProcessor::processStylesheet(&xslDocument, + &mVariables, &ps); + } + else { + nsCOMPtr styleElem = do_QueryInterface(mStylesheet); + NS_ENSURE_TRUE(styleElem, NS_ERROR_FAILURE); + Element* element = xslDocument.createElement(styleElem); + NS_ENSURE_TRUE(element, NS_ERROR_OUT_OF_MEMORY); + rv = txXSLTProcessor::processTopLevel(element, &mVariables, + &ps); + } + NS_ENSURE_SUCCESS(rv, rv); + + rv = aOutput->CreateDocumentFragment(aResult); + NS_ENSURE_SUCCESS(rv, rv); + txToFragmentHandlerFactory handlerFactory(*aResult); + ps.mOutputHandlerFactory = &handlerFactory; + + // Process root of XML source document + txXSLTProcessor::transform(&ps); + + return NS_OK; +} + +NS_IMETHODIMP +txMozillaXSLTProcessor::SetParameter(const nsAString & aNamespaceURI, + const nsAString & aLocalName, + nsIVariant *aValue) +{ + NS_ENSURE_ARG(aValue); + PRUint16 dataType; + aValue->GetDataType(&dataType); + switch (dataType) { + // Number + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + + // Boolean + case nsIDataType::VTYPE_BOOL: + + // String + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_WCHAR: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_ASTRING: + + // Nodeset + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + case nsIDataType::VTYPE_ARRAY: + { + // This might still be an error, but we'll only + // find out later since we lazily evaluate. + break; + } + + default: + { + return NS_ERROR_FAILURE; + } + } + + nsresult rv; + nsCOMPtr namespaceManager = + do_GetService(kNameSpaceManagerCID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + PRInt32 nsId = kNameSpaceID_Unknown; + rv = namespaceManager->RegisterNameSpace(aNamespaceURI, nsId); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr localName = do_GetAtom(aLocalName); + txExpandedName varName(nsId, localName); + + txVariable* var = (txVariable*)mVariables.get(varName); + if (var) { + var->setValue(aValue); + return NS_OK; + } + + var = new txVariable(aValue); + NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY); + + return mVariables.add(varName, var); +} + +NS_IMETHODIMP +txMozillaXSLTProcessor::GetParameter(const nsAString& aNamespaceURI, + const nsAString& aLocalName, + nsIVariant **aResult) +{ + nsresult rv; + nsCOMPtr namespaceManager = + do_GetService(kNameSpaceManagerCID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + PRInt32 nsId = kNameSpaceID_Unknown; + rv = namespaceManager->RegisterNameSpace(aNamespaceURI, nsId); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr localName = do_GetAtom(aLocalName); + txExpandedName varName(nsId, localName); + + txVariable* var = (txVariable*)mVariables.get(varName); + if (var) { + return var->getValue(aResult); + } + return NS_OK; +} + +NS_IMETHODIMP +txMozillaXSLTProcessor::RemoveParameter(const nsAString& aNamespaceURI, + const nsAString& aLocalName) +{ + nsresult rv; + nsCOMPtr namespaceManager = + do_GetService(kNameSpaceManagerCID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + PRInt32 nsId = kNameSpaceID_Unknown; + rv = namespaceManager->RegisterNameSpace(aNamespaceURI, nsId); + nsCOMPtr localName = do_GetAtom(aLocalName); + txExpandedName varName(nsId, localName); + + mVariables.remove(varName); + return NS_OK; +} + +NS_IMETHODIMP +txMozillaXSLTProcessor::ClearParameters() +{ + mVariables.clear(); + + return NS_OK; +} + +/* static*/ +nsresult +txVariable::Convert(nsIVariant *aValue, ExprResult** aResult) +{ + *aResult = nsnull; + + PRUint16 dataType; + aValue->GetDataType(&dataType); + switch (dataType) { + // Number + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + { + double value; + nsresult rv = aValue->GetAsDouble(&value); + NS_ENSURE_SUCCESS(rv, rv); + + *aResult = new NumberResult(value); + NS_ENSURE_TRUE(aResult, NS_ERROR_OUT_OF_MEMORY); + + return NS_OK; + } + + // Boolean + case nsIDataType::VTYPE_BOOL: + { + PRBool value; + nsresult rv = aValue->GetAsBool(&value); + NS_ENSURE_SUCCESS(rv, rv); + + *aResult = new BooleanResult(value); + NS_ENSURE_TRUE(aResult, NS_ERROR_OUT_OF_MEMORY); + + return NS_OK; + } + + // String + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_WCHAR: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_ASTRING: + { + String value; + nsresult rv = aValue->GetAsAString(value); + NS_ENSURE_SUCCESS(rv, rv); + + *aResult = new StringResult(value); + NS_ENSURE_TRUE(aResult, NS_ERROR_OUT_OF_MEMORY); + + return NS_OK; + } + + // Nodeset + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + { + nsID *iid; + nsCOMPtr supports; + nsresult rv = aValue->GetAsInterface(&iid, getter_AddRefs(supports)); + NS_ENSURE_SUCCESS(rv, rv); + if (iid) { + // XXX Figure out what the user added and if we can do + // anything with it. + // nsIDOMNode, nsIDOMNodeList, nsIDOMXPathResult + nsMemory::Free(iid); + } + break; + } + + case nsIDataType::VTYPE_ARRAY: + { + // XXX Figure out what the user added and if we can do + // anything with it. Array of Nodes. + break; + } + } + return NS_ERROR_ILLEGAL_VALUE; +} diff --git a/content/xslt/src/xslt/txMozillaXSLTProcessor.h b/content/xslt/src/xslt/txMozillaXSLTProcessor.h new file mode 100644 index 000000000000..de391c596757 --- /dev/null +++ b/content/xslt/src/xslt/txMozillaXSLTProcessor.h @@ -0,0 +1,147 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Van der Beken (original author) + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef TRANSFRMX_TXMOZILLAXSLTPROCESSOR_H +#define TRANSFRMX_TXMOZILLAXSLTPROCESSOR_H + +#include "ExprResult.h" +#include "nsIDocumentTransformer.h" +#include "nsIVariant.h" +#include "nsIXSLTProcessor.h" +#include "nsVoidArray.h" +#include "nsWeakPtr.h" +#include "txExpandedNameMap.h" +#include "XSLTProcessor.h" +#include "nsIDOMNode.h" +#include "txXMLEventHandler.h" +#include "nsIDOMDocument.h" +#include "nsIDOMDocumentFragment.h" +#include "nsIXSLTProcessorObsolete.h" + +/* bacd8ad0-552f-11d3-a9f7-000064657374 */ +#define TRANSFORMIIX_XSLT_PROCESSOR_CID \ +{ 0xbacd8ad0, 0x552f, 0x11d3, {0xa9, 0xf7, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74} } + +#define TRANSFORMIIX_XSLT_PROCESSOR_CONTRACTID \ +"@mozilla.org/document-transformer;1?type=text/xsl" + +class txVariable : public txIGlobalParameter +{ +public: + txVariable(nsIVariant *aValue) : mValue(aValue), + mTxValue(nsnull) + { + } + ~txVariable() + { + delete mTxValue; + } + nsresult getValue(ExprResult** aValue) + { + NS_ASSERTION(mValue, "variablevalue is null"); + + if (!mTxValue) { + nsresult rv = Convert(mValue, &mTxValue); + NS_ENSURE_SUCCESS(rv, rv); + } + + *aValue = mTxValue; + + return NS_OK; + } + nsresult getValue(nsIVariant** aValue) + { + *aValue = mValue; + NS_ADDREF(*aValue); + return NS_OK; + } + void setValue(nsIVariant* aValue) + { + NS_ASSERTION(aValue, "setting variablevalue to null"); + mValue = aValue; + delete mTxValue; + mTxValue = nsnull; + } + +private: + static nsresult Convert(nsIVariant *aValue, ExprResult** aResult); + + nsCOMPtr mValue; + ExprResult* mTxValue; +}; + +/** + * txMozillaXSLTProcessor is a front-end to the XSLT Processor. + */ +class txMozillaXSLTProcessor : public nsIXSLTProcessor, + public nsIXSLTProcessorObsolete, + public nsIDocumentTransformer +{ +public: + /** + * Creates a new txMozillaXSLTProcessor + */ + txMozillaXSLTProcessor(); + + /** + * Default destructor for txMozillaXSLTProcessor + */ + virtual ~txMozillaXSLTProcessor(); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIXSLTProcessor interface + NS_DECL_NSIXSLTPROCESSOR + + // nsIXSLTProcessorObsolete interface + NS_DECL_NSIXSLTPROCESSOROBSOLETE + + // nsIDocumentTransformer interface + NS_IMETHOD TransformDocument(nsIDOMNode *aSourceDOM, + nsIDOMNode *aStyleDOM, + nsITransformObserver *aObserver, + nsIDOMDocument **_retval); + +protected: + nsCOMPtr mStylesheet; + txExpandedNameMap mVariables; +}; + +#endif diff --git a/content/xslt/src/xslt/txStandaloneXSLTProcessor.cpp b/content/xslt/src/xslt/txStandaloneXSLTProcessor.cpp new file mode 100644 index 000000000000..dd89879cb560 --- /dev/null +++ b/content/xslt/src/xslt/txStandaloneXSLTProcessor.cpp @@ -0,0 +1,359 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Van der Beken (original author) + * Axel Hecht + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "txStandaloneXSLTProcessor.h" +#include "txURIUtils.h" +#include "XMLParser.h" +#include "txSingleNodeContext.h" +#include "Names.h" +#include "txUnknownHandler.h" +#include "txHTMLOutput.h" +#include "txTextOutput.h" + +/** + * Output Handler Factory + */ +class txStandaloneHandlerFactory : public txIOutputHandlerFactory +{ +public: + txStandaloneHandlerFactory(ProcessorState* aPs, + ostream* aStream) + : mPs(aPs), mStream(aStream) + { + } + + virtual ~txStandaloneHandlerFactory() + { + }; + + TX_DECL_TXIOUTPUTHANDLERFACTORY; + +private: + ProcessorState* mPs; + ostream* mStream; +}; + +nsresult +txStandaloneHandlerFactory::createHandlerWith(txOutputFormat* aFormat, + txIOutputXMLEventHandler** aHandler) +{ + *aHandler = 0; + switch (aFormat->mMethod) { + case eXMLOutput: + *aHandler = new txXMLOutput(aFormat, mStream); + break; + + case eHTMLOutput: + *aHandler = new txHTMLOutput(aFormat, mStream); + break; + + case eTextOutput: + *aHandler = new txTextOutput(mStream); + break; + + case eMethodNotSet: + *aHandler = new txUnknownHandler(mPs); + break; + } + NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY); + return NS_OK; +} + +nsresult +txStandaloneHandlerFactory::createHandlerWith(txOutputFormat* aFormat, + const String& aName, + PRInt32 aNsID, + txIOutputXMLEventHandler** aHandler) +{ + *aHandler = 0; + NS_ASSERTION(aFormat->mMethod != eMethodNotSet, + "How can method not be known when root element is?"); + NS_ENSURE_TRUE(aFormat->mMethod != eMethodNotSet, NS_ERROR_UNEXPECTED); + return createHandlerWith(aFormat, aHandler); +} + + +/** + * txStandaloneXSLTProcessor + */ + +/** + * Transform a XML document given by path. + * The stylesheet is retrieved by a processing instruction, + * or an error is returned. + */ +nsresult +txStandaloneXSLTProcessor::transform(String& aXMLPath, ostream& aOut, + ErrorObserver& aErr) +{ + Document* xmlDoc = parsePath(aXMLPath, aErr); + if (!xmlDoc) { + return NS_ERROR_FAILURE; + } + + // transform + nsresult rv = transform(xmlDoc, aOut, aErr); + + delete xmlDoc; + + return rv; +} + +/** + * Transform a XML document given by path with the given + * stylesheet. + */ +nsresult +txStandaloneXSLTProcessor::transform(String& aXMLPath, String& aXSLPath, + ostream& aOut, ErrorObserver& aErr) +{ + Document* xmlDoc = parsePath(aXMLPath, aErr); + if (!xmlDoc) { + return NS_ERROR_FAILURE; + } + Document* xslDoc = parsePath(aXSLPath, aErr); + if (!xslDoc) { + delete xmlDoc; + return NS_ERROR_FAILURE; + } + // transform + nsresult rv = transform(xmlDoc, xslDoc, aOut, aErr); + + delete xmlDoc; + delete xslDoc; + + return rv; +} + +/** + * Transform a XML document. + * The stylesheet is retrieved by a processing instruction, + * or an error is returned. + */ +nsresult +txStandaloneXSLTProcessor::transform(Document* aXMLDoc, ostream& aOut, + ErrorObserver& aErr) +{ + if (!aXMLDoc) { + return NS_ERROR_INVALID_POINTER; + } + + // get stylesheet path + String stylePath; + getHrefFromStylesheetPI(*aXMLDoc, stylePath); + + Document* xslDoc = parsePath(stylePath, aErr); + if (!xslDoc) { + return NS_ERROR_FAILURE; + } + + // transform + nsresult rv = transform(aXMLDoc, xslDoc, aOut, aErr); + + delete xslDoc; + return rv; +} + +/** + * Processes the given XML Document using the given XSL document + * and prints the results to the given ostream argument + */ +nsresult +txStandaloneXSLTProcessor::transform(Document* aSource, Node* aStylesheet, + ostream& aOut, ErrorObserver& aErr) +{ + // Create a new ProcessorState + Document* stylesheetDoc = 0; + Element* stylesheetElem = 0; + if (aStylesheet->getNodeType() == Node::DOCUMENT_NODE) { + stylesheetDoc = (Document*)aStylesheet; + } + else { + stylesheetElem = (Element*)aStylesheet; + stylesheetDoc = aStylesheet->getOwnerDocument(); + } + ProcessorState ps(aSource, stylesheetDoc); + + ps.addErrorObserver(aErr); + + txSingleNodeContext evalContext(aSource, &ps); + ps.setEvalContext(&evalContext); + + // Index templates and process top level xsl elements + nsresult rv = NS_OK; + if (stylesheetElem) { + rv = processTopLevel(stylesheetElem, 0, &ps); + } + else { + rv = processStylesheet(stylesheetDoc, 0, &ps); + } + if (NS_FAILED(rv)) { + return rv; + } + + txStandaloneHandlerFactory handlerFactory(&ps, &aOut); + ps.mOutputHandlerFactory = &handlerFactory; + +#ifndef XP_WIN + bool sync = aOut.sync_with_stdio(false); +#endif + // Process root of XML source document + txXSLTProcessor::transform(&ps); +#ifndef XP_WIN + aOut.sync_with_stdio(sync); +#endif + + return NS_OK; +} + +/** + * Parses all XML Stylesheet PIs associated with the + * given XML document. If any stylesheet PIs are found with + * type="text/xsl" the href psuedo attribute value will be + * added to the given href argument. If multiple text/xsl stylesheet PIs + * are found, the one closest to the end of the document is used. + */ +void txStandaloneXSLTProcessor::getHrefFromStylesheetPI(Document& xmlDocument, + String& href) +{ + Node* node = xmlDocument.getFirstChild(); + String type; + String tmpHref; + while (node) { + if (node->getNodeType() == Node::PROCESSING_INSTRUCTION_NODE) { + String target = ((ProcessingInstruction*)node)->getTarget(); + if (STYLESHEET_PI.isEqual(target) || + STYLESHEET_PI_OLD.isEqual(target)) { + String data = ((ProcessingInstruction*)node)->getData(); + type.clear(); + tmpHref.clear(); + parseStylesheetPI(data, type, tmpHref); + if (XSL_MIME_TYPE.isEqual(type)) { + href.clear(); + URIUtils::resolveHref(tmpHref, node->getBaseURI(), href); + } + } + } + node = node->getNextSibling(); + } + +} + +/** + * Parses the contents of data, and returns the type and href pseudo attributes + */ +void txStandaloneXSLTProcessor::parseStylesheetPI(String& data, + String& type, + String& href) +{ + PRUint32 size = data.length(); + NamedMap bufferMap; + bufferMap.put(String("type"), &type); + bufferMap.put(String("href"), &href); + PRUint32 ccount = 0; + MBool inLiteral = MB_FALSE; + char matchQuote = '"'; + String sink; + String* buffer = &sink; + + for (ccount = 0; ccount < size; ccount++) { + char ch = data.charAt(ccount); + switch ( ch ) { + case ' ': + if (inLiteral) { + buffer->append(ch); + } + break; + case '=': + if (inLiteral) { + buffer->append(ch); + } + else if (buffer->length() > 0) { + buffer = (String*)bufferMap.get(*buffer); + if (!buffer) { + sink.clear(); + buffer = &sink; + } + } + break; + case '"': + case '\'': + if (inLiteral) { + if (matchQuote == ch) { + inLiteral = MB_FALSE; + sink.clear(); + buffer = &sink; + } + else { + buffer->append(ch); + } + } + else { + inLiteral = MB_TRUE; + matchQuote = ch; + } + break; + default: + buffer->append(ch); + break; + } + } +} + +Document* +txStandaloneXSLTProcessor::parsePath(const String& aPath, ErrorObserver& aErr) +{ + ifstream xmlInput(NS_LossyConvertUCS2toASCII(aPath).get(), ios::in); + if (!xmlInput) { + String err("Couldn't open "); + err.append(aPath); + aErr.receiveError(err); + return 0; + } + // parse source + XMLParser xmlParser; + Document* xmlDoc = xmlParser.parse(xmlInput, aPath); + if (!xmlDoc) { + String err("Parsing error in "); + err.append(aPath); + aErr.receiveError(err); + } + return xmlDoc; +} diff --git a/content/xslt/src/xslt/txStandaloneXSLTProcessor.h b/content/xslt/src/xslt/txStandaloneXSLTProcessor.h new file mode 100644 index 000000000000..90c5e8beeed9 --- /dev/null +++ b/content/xslt/src/xslt/txStandaloneXSLTProcessor.h @@ -0,0 +1,162 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Van der Beken (original author) + * Axel Hecht + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef TRANSFRMX_TXSTANDALONEXSLTPROCESSOR_H +#define TRANSFRMX_TXSTANDALONEXSLTPROCESSOR_H + +#include "XSLTProcessor.h" +#ifndef __BORLANDC__ +#include +#include +#endif + +class txStreamXMLEventHandler; + +/** + * txStandaloneXSLTProcessor + * + * Use of the standalone TransforMiiX API: + * + * The XSLT Processor need initialisation and shutdown + * by + * txStandaloneXSLTProcessor::Init(); + * and + * txStandaloneXSLTProcessor::Shutdown(); + * Be sure to always call these functions in pairs. + * + * The API to transform documents consists of entry points + * to transform either one or two documents. + * If you provide one document, the stylesheet location is + * computed from the processing instruction. If that cannot + * be found, an error is issued. + * + * The result is output to a stream. + * + * Documents can be provided either by path or by DOM Document. + * + * Stylesheet parameters + * XXX TODO + * + */ + +class txStandaloneXSLTProcessor : public txXSLTProcessor +{ +public: + /** + * Methods that print the result to a stream + */ + + /** + * Transform a XML document given by path. + * The stylesheet is retrieved by a processing instruction, + * or an error is returned. + * + * @param aXMLPath path to the source document + * @param aOut stream to which the result is feeded + * @param aErr error observer + * @result NS_OK if transformation was successful + */ + nsresult transform(String& aXMLPath, ostream& aOut, ErrorObserver& aErr); + + /** + * Transform a XML document given by path with the given + * stylesheet. + * + * @param aXMLPath path to the source document + * @param aXSLPath path to the style document + * @param aOut stream to which the result is feeded + * @param aErr error observer + * @result NS_OK if transformation was successful + */ + nsresult transform(String& aXMLPath, String& aXSLPath, ostream& aOut, + ErrorObserver& aErr); + + /** + * Transform a XML document. + * The stylesheet is retrieved by a processing instruction, + * or an error is returned. + * + * @param aXMLDoc source document + * @param aOut stream to which the result is feeded + * @param aErr error observer + * @result NS_OK if transformation was successful + */ + nsresult transform(Document* aXMLDoc, ostream& aOut, ErrorObserver& aErr); + + /** + * Transform a XML document with the given stylesheet. + * + * @param aXMLDoc source document + * @param aXSLNode style node + * @param aOut stream to which the result is feeded + * @param aErr error observer + * @result NS_OK if transformation was successful + */ + nsresult transform(Document* aXMLDoc, Node* aXSLNode, + ostream& aOut, ErrorObserver& aErr); + +protected: + /** + * Parses all XML Stylesheet PIs associated with the + * given XML document. If any stylesheet PIs are found with + * type="text/xsl" the href psuedo attribute value will be + * added to the given href argument. If multiple text/xsl stylesheet PIs + * are found, the one closest to the end of the document is used. + */ + static void getHrefFromStylesheetPI(Document& xmlDocument, String& href); + + /** + * Parses the contents of data, returns the type and href psuedo attributes + */ + static void parseStylesheetPI(String& data, + String& type, + String& href); + + /** + * Create a Document from a path. + * + * @param aPath path to the xml file + * @param aErr ErrorObserver + * @result Document XML Document, or null on error + */ + static Document* parsePath(const String& aPath, ErrorObserver& aErr); +}; + +#endif diff --git a/content/xslt/src/xslt/txTextOutput.cpp b/content/xslt/src/xslt/txTextOutput.cpp index 5bd3252575c2..63da8d26235d 100644 --- a/content/xslt/src/xslt/txTextOutput.cpp +++ b/content/xslt/src/xslt/txTextOutput.cpp @@ -39,7 +39,8 @@ #include "txTextOutput.h" #include "TxString.h" -txTextOutput::txTextOutput() +txTextOutput::txTextOutput(ostream* aOut) + : mOut(aOut) { } @@ -89,21 +90,3 @@ void txTextOutput::startElement(const String& aName, const PRInt32 aNsID) { } - -void txTextOutput::getOutputStream(ostream** aOutputStream) -{ - if (aOutputStream) - *aOutputStream = mOut; -} - -void txTextOutput::setOutputStream(ostream* aOutputStream) -{ - mOut = aOutputStream; -} - -void txTextOutput::setOutputFormat(txOutputFormat* aOutputFormat) -{ - mOutputFormat.reset(); - mOutputFormat.merge(*aOutputFormat); - mOutputFormat.setFromDefaults(); -} diff --git a/content/xslt/src/xslt/txTextOutput.h b/content/xslt/src/xslt/txTextOutput.h index ce3427237e63..46e5b122ca1b 100644 --- a/content/xslt/src/xslt/txTextOutput.h +++ b/content/xslt/src/xslt/txTextOutput.h @@ -42,10 +42,10 @@ #include "txXMLEventHandler.h" #include "txOutputFormat.h" -class txTextOutput : public txStreamXMLEventHandler +class txTextOutput : public txIOutputXMLEventHandler { public: - txTextOutput(); + txTextOutput(ostream* aOut); ~txTextOutput(); /* @@ -95,6 +95,18 @@ public: void endElement(const String& aName, const PRInt32 aNsID); + /** + * Returns whether the output handler supports + * disable-output-escaping. + * + * @return MB_TRUE if this handler supports + * disable-output-escaping + */ + MBool hasDisableOutputEscaping() + { + return MB_TRUE; + } + /* * Signals to receive a processing instruction. * @@ -118,30 +130,8 @@ public: void startElement(const String& aName, const PRInt32 aNsID); - /* - * Sets the output format. - * - * @param aOutputFormat the output format - */ - void setOutputFormat(txOutputFormat* aOutputFormat); - - /** - * Get the output stream. - * - * @param aOutputStream the current output stream - */ - void getOutputStream(ostream** aOutputStream); - - /** - * Sets the output stream. - * - * @param aDocument the Mozilla output document - */ - void setOutputStream(ostream* aOutputStream); - private: ostream* mOut; - txOutputFormat mOutputFormat; }; #endif diff --git a/content/xslt/src/xslt/txUnknownHandler.cpp b/content/xslt/src/xslt/txUnknownHandler.cpp index 1954e4e6c741..5c39e1269236 100644 --- a/content/xslt/src/xslt/txUnknownHandler.cpp +++ b/content/xslt/src/xslt/txUnknownHandler.cpp @@ -38,12 +38,22 @@ #include "txUnknownHandler.h" #include +#include "ProcessorState.h" + +#ifndef TX_EXE +NS_IMPL_ISUPPORTS1(txUnknownHandler, txIOutputXMLEventHandler); +#endif PRUint32 txUnknownHandler::kReasonableTransactions = 8; -txUnknownHandler::txUnknownHandler() : mTotal(0), - mMax(kReasonableTransactions) +txUnknownHandler::txUnknownHandler(ProcessorState* aPs) + : mTotal(0), mMax(kReasonableTransactions), + mPs(aPs) { +#ifndef TX_EXE + NS_INIT_ISUPPORTS(); +#endif + mArray = new txOutputTransaction*[kReasonableTransactions]; } @@ -60,7 +70,9 @@ void txUnknownHandler::attribute(const String& aName, const PRInt32 aNsID, const String& aValue) { - NS_ASSERTION(0, "This shouldn't be called") + // If this is called then the stylesheet is trying to add an attribute + // without adding an element first. So we'll just ignore it. + // XXX ErrorReport: Signal this? } void txUnknownHandler::characters(const String& aData) @@ -69,7 +81,7 @@ void txUnknownHandler::characters(const String& aData) new txOneStringTransaction(txOutputTransaction::eCharacterTransaction, aData); if (!transaction) { - NS_ASSERTION(0, "Out of memory!") + NS_ASSERTION(0, "Out of memory!"); return; } addTransaction(transaction); @@ -81,7 +93,7 @@ void txUnknownHandler::charactersNoOutputEscaping(const String& aData) new txOneStringTransaction(txOutputTransaction::eCharacterNoOETransaction, aData); if (!transaction) { - NS_ASSERTION(0, "Out of memory!") + NS_ASSERTION(0, "Out of memory!"); return; } addTransaction(transaction); @@ -93,7 +105,7 @@ void txUnknownHandler::comment(const String& aData) new txOneStringTransaction(txOutputTransaction::eCommentTransaction, aData); if (!transaction) { - NS_ASSERTION(0, "Out of memory!") + NS_ASSERTION(0, "Out of memory!"); return; } addTransaction(transaction); @@ -101,19 +113,32 @@ void txUnknownHandler::comment(const String& aData) void txUnknownHandler::endDocument() { - txOutputTransaction* transaction = - new txOutputTransaction(txOutputTransaction::eEndDocumentTransaction); - if (!transaction) { - NS_ASSERTION(0, "Out of memory!") + // This is an unusual case, no output method has been set and we + // didn't create a document element. Switching to XML output mode + // anyway. + +#ifndef TX_EXE + // Make sure that we don't get deleted while this function is executed and + // we set a new outputhandler + nsCOMPtr kungFuDeathGrip(this); +#endif + nsresult rv = createHandlerAndFlush(eXMLOutput, String(), + kNameSpaceID_None); + if (NS_FAILED(rv)) return; - } - addTransaction(transaction); + + mPs->mResultHandler->endDocument(); + + // in module the outputhandler is refcounted +#ifdef TX_EXE + delete this; +#endif } void txUnknownHandler::endElement(const String& aName, const PRInt32 aNsID) { - NS_ASSERTION(0, "This shouldn't be called") + NS_ASSERTION(0, "This shouldn't be called"); } void txUnknownHandler::processingInstruction(const String& aTarget, @@ -123,7 +148,7 @@ void txUnknownHandler::processingInstruction(const String& aTarget, new txTwoStringTransaction(txOutputTransaction::ePITransaction, aTarget, aData); if (!transaction) { - NS_ASSERTION(0, "Out of memory!") + NS_ASSERTION(0, "Out of memory!"); return; } addTransaction(transaction); @@ -134,7 +159,7 @@ void txUnknownHandler::startDocument() txOutputTransaction* transaction = new txOutputTransaction(txOutputTransaction::eStartDocumentTransaction); if (!transaction) { - NS_ASSERTION(0, "Out of memory!") + NS_ASSERTION(0, "Out of memory!"); return; } addTransaction(transaction); @@ -143,74 +168,108 @@ void txUnknownHandler::startDocument() void txUnknownHandler::startElement(const String& aName, const PRInt32 aNsID) { - NS_ASSERTION(0, "This shouldn't be called") -} +#ifndef TX_EXE + // Make sure that we don't get deleted while this function is executed and + // we set a new outputhandler + nsCOMPtr kungFuDeathGrip(this); +#endif -void txUnknownHandler::setOutputFormat(txOutputFormat* aOutputFormat) -{ -} - -void txUnknownHandler::getOutputStream(ostream** aOutputStream) -{ - if (aOutputStream) { - *aOutputStream = mOut; + nsresult rv = NS_OK; + txOutputFormat* format = mPs->getOutputFormat(); + if (format->mMethod != eMethodNotSet) { + rv = createHandlerAndFlush(format->mMethod, aName, aNsID); } + else if (aNsID == kNameSpaceID_None && + aName.isEqualIgnoreCase(String("html"))) { + rv = createHandlerAndFlush(eHTMLOutput, aName, aNsID); + } + else { + rv = createHandlerAndFlush(eXMLOutput, aName, aNsID); + } + if (NS_FAILED(rv)) + return; + + mPs->mResultHandler->startElement(aName, aNsID); + + // in module the outputhandler is refcounted +#ifdef TX_EXE + delete this; +#endif } -void txUnknownHandler::setOutputStream(ostream* aOutputStream) +#ifndef TX_EXE +void txUnknownHandler::getOutputDocument(nsIDOMDocument** aDocument) { - mOut = aOutputStream; + *aDocument = nsnull; } +#endif -void txUnknownHandler::flush(txStreamXMLEventHandler* aHandler) +nsresult txUnknownHandler::createHandlerAndFlush(txOutputMethod aMethod, + const String& aName, + const PRInt32 aNsID) { + nsresult rv = NS_OK; + txOutputFormat* format = mPs->getOutputFormat(); + format->mMethod = aMethod; + + txIOutputXMLEventHandler* handler = 0; + rv = mPs->mOutputHandlerFactory->createHandlerWith(format, aName, aNsID, + &handler); + NS_ENSURE_SUCCESS(rv, rv); + + mPs->mOutputHandler = handler; + mPs->mResultHandler = handler; + + MBool hasDOE = handler->hasDisableOutputEscaping(); + PRUint32 counter; for (counter = 0; counter < mTotal; ++counter) { switch (mArray[counter]->mType) { case txOutputTransaction::eCharacterTransaction: { txOneStringTransaction* transaction = (txOneStringTransaction*)mArray[counter]; - aHandler->characters(transaction->mString); + handler->characters(transaction->mString); delete transaction; break; } case txOutputTransaction::eCharacterNoOETransaction: { txOneStringTransaction* transaction = (txOneStringTransaction*)mArray[counter]; - aHandler->charactersNoOutputEscaping(transaction->mString); + if (hasDOE) { + handler->charactersNoOutputEscaping(transaction->mString); + } + else { + handler->characters(transaction->mString); + } delete transaction; break; } case txOutputTransaction::eCommentTransaction: { txOneStringTransaction* transaction = (txOneStringTransaction*)mArray[counter]; - aHandler->comment(transaction->mString); + handler->comment(transaction->mString); delete transaction; break; } - case txOutputTransaction::eEndDocumentTransaction: - { - aHandler->endDocument(); - delete mArray[counter]; - break; - } case txOutputTransaction::ePITransaction: { txTwoStringTransaction* transaction = (txTwoStringTransaction*)mArray[counter]; - aHandler->processingInstruction(transaction->mStringOne, + handler->processingInstruction(transaction->mStringOne, transaction->mStringTwo); delete transaction; break; } case txOutputTransaction::eStartDocumentTransaction: { - aHandler->startDocument(); + handler->startDocument(); delete mArray[counter]; break; } } } mTotal = 0; + + return NS_OK; } void txUnknownHandler::addTransaction(txOutputTransaction* aTransaction) @@ -219,7 +278,7 @@ void txUnknownHandler::addTransaction(txOutputTransaction* aTransaction) PRUint32 newMax = mMax * 2; txOutputTransaction** newArray = new txOutputTransaction*[newMax]; if (!newArray) { - NS_ASSERTION(0, "Out of memory!") + NS_ASSERTION(0, "Out of memory!"); return; } mMax = newMax; diff --git a/content/xslt/src/xslt/txUnknownHandler.h b/content/xslt/src/xslt/txUnknownHandler.h index d361b59516cf..173f88108d2d 100644 --- a/content/xslt/src/xslt/txUnknownHandler.h +++ b/content/xslt/src/xslt/txUnknownHandler.h @@ -41,6 +41,9 @@ #include "txXMLEventHandler.h" #include "TxString.h" +#include "txOutputFormat.h" + +class ProcessorState; class txOutputTransaction { @@ -49,7 +52,6 @@ public: eCharacterTransaction, eCharacterNoOETransaction, eCommentTransaction, - eEndDocumentTransaction, ePITransaction, eStartDocumentTransaction }; @@ -90,12 +92,16 @@ public: String mStringTwo; }; -class txUnknownHandler : public txStreamXMLEventHandler +class txUnknownHandler : public txIOutputXMLEventHandler { public: - txUnknownHandler(); + txUnknownHandler(ProcessorState* aPs); virtual ~txUnknownHandler(); +#ifndef TX_EXE + NS_DECL_ISUPPORTS +#endif + /* * Signals to receive the start of an attribute. * @@ -143,6 +149,18 @@ public: void endElement(const String& aName, const PRInt32 aNsID); + /** + * Returns whether the output handler supports + * disable-output-escaping. + * + * @return MB_TRUE if this handler supports + * disable-output-escaping + */ + MBool hasDisableOutputEscaping() + { + return MB_TRUE; + } + /* * Signals to receive a processing instruction. * @@ -165,34 +183,29 @@ public: */ void startElement(const String& aName, const PRInt32 aNsID); - /* - * Sets the output format. - * - * @param aOutputFormat the output format - */ - void setOutputFormat(txOutputFormat* aOutputFormat); +#ifndef TX_EXE /** - * Get the output stream. + * Gets the Mozilla output document * - * @param aOutputStream the current output stream + * @param aDocument the Mozilla output document */ - void getOutputStream(ostream** aOutputStream); - - /* - * Sets the output stream. - * - * @param aOutputStream the output stream - */ - void setOutputStream(ostream* aOutputStream); - - void flush(txStreamXMLEventHandler* aHandler); + void getOutputDocument(nsIDOMDocument** aDocument); +#endif private: + nsresult createHandlerAndFlush(txOutputMethod aMethod, + const String& aName, + const PRInt32 aNsID); void addTransaction(txOutputTransaction* aTransaction); PRUint32 mTotal, mMax; - ostream* mOut; + /* + * XXX we shouldn't hold to the ProcessorState, as we're supposed + * to live without it. But as a standalone handler, we don't. + * The right fix may need a txOutputFormat here. + */ + ProcessorState* mPs; txOutputTransaction** mArray; static PRUint32 kReasonableTransactions; diff --git a/content/xslt/src/xslt/txXMLEventHandler.h b/content/xslt/src/xslt/txXMLEventHandler.h index 6b3e878d7640..48e18f090cd1 100644 --- a/content/xslt/src/xslt/txXMLEventHandler.h +++ b/content/xslt/src/xslt/txXMLEventHandler.h @@ -25,14 +25,20 @@ #define TRANSFRMX_XML_EVENT_HANDLER_H #include "baseutils.h" +#include "txError.h" class String; class txOutputFormat; #ifdef TX_EXE #include #else +#include "nsISupports.h" +#define kTXNameSpaceURI "http://www.mozilla.org/TransforMiix" +#define kTXWrapper "transformiix:result" + class nsIContent; class nsIDOMDocument; class nsIDOMHTMLScriptElement; +class nsITransformObserver; #endif /** @@ -109,79 +115,84 @@ public: const PRInt32 aNsID) = 0; }; -class txOutputXMLEventHandler : public txXMLEventHandler -{ -public: - /** - * Sets the output format. - * - * @param aOutputFormat the output format - */ - virtual void setOutputFormat(txOutputFormat* aOutputFormat) = 0; -}; - #ifdef TX_EXE -class txStreamXMLEventHandler : public txOutputXMLEventHandler +class txIOutputXMLEventHandler : public txXMLEventHandler +#else +#define TX_IOUTPUTXMLEVENTHANDLER_IID \ +{ 0x80e5e802, 0x8c88, 0x11d6, \ + { 0xa7, 0xf2, 0xc5, 0xc3, 0x85, 0x6b, 0xbb, 0xbc }} + +class txIOutputXMLEventHandler : public nsISupports, + public txXMLEventHandler +#endif { public: - /** - * Get the output stream. - * - * @param aOutputStream the current output stream - */ - virtual void getOutputStream(ostream** aOutputStream) = 0; - - /** - * Sets the output stream. - * - * @param aOutputStream the output stream - */ - virtual void setOutputStream(ostream* aOutputStream) = 0; - /** * Signals to receive characters that don't need output escaping. * * @param aData the characters to receive */ virtual void charactersNoOutputEscaping(const String& aData) = 0; -}; -#else -class txMozillaXMLEventHandler : public txOutputXMLEventHandler -{ -public: - /** - * Disables loading of stylesheets. - */ - virtual void disableStylesheetLoad() = 0; /** - * Returns the root content of the result. + * Returns whether the output handler supports + * disable-output-escaping. * - * @param aReturn the root content + * @return MB_TRUE if this handler supports + * disable-output-escaping */ - virtual nsresult getRootContent(nsIContent** aReturn) = 0; + virtual MBool hasDisableOutputEscaping() = 0; + +#ifndef TX_EXE + NS_DEFINE_STATIC_IID_ACCESSOR(TX_IOUTPUTXMLEVENTHANDLER_IID) /** - * Returns PR_TRUE if the event handler has finished anything - * extra that had to happen after the transform has finished. - */ - virtual PRBool isDone() = 0; - - /** - * Removes a script element from the array of elements that are - * still loading. - * - * @param aReturn the script element to remove - */ - virtual void removeScriptElement(nsIDOMHTMLScriptElement *aElement) = 0; - - /** - * Sets the Mozilla output document. + * Gets the Mozilla output document * * @param aDocument the Mozilla output document */ - virtual void setOutputDocument(nsIDOMDocument* aDocument) = 0; -}; + virtual void getOutputDocument(nsIDOMDocument** aDocument) = 0; #endif +}; + +/** + * Interface used to create the appropriate outputhandler + */ +class txIOutputHandlerFactory +{ +public: + virtual ~txIOutputHandlerFactory() {}; + + /** + * Creates an outputhandler for the specified format. + * @param aFromat format to get handler for + * @param aHandler outparam. The created handler + */ + virtual nsresult + createHandlerWith(txOutputFormat* aFormat, + txIOutputXMLEventHandler** aHandler) = 0; + + /** + * Creates an outputhandler for the specified format, with the specified + * name and namespace for the root element. + * @param aFromat format to get handler for + * @param aName name of the root element + * @param aNsID namespace-id of the root element + * @param aHandler outparam. The created handler + */ + virtual nsresult + createHandlerWith(txOutputFormat* aFormat, + const String& aName, + PRInt32 aNsID, + txIOutputXMLEventHandler** aHandler) = 0; +}; + +#define TX_DECL_TXIOUTPUTHANDLERFACTORY \ + nsresult createHandlerWith(txOutputFormat* aFormat, \ + txIOutputXMLEventHandler** aHandler); \ + nsresult createHandlerWith(txOutputFormat* aFormat, \ + const String& aName, \ + PRInt32 aNsID, \ + txIOutputXMLEventHandler** aHandler) \ #endif diff --git a/content/xslt/src/xslt/txXMLOutput.cpp b/content/xslt/src/xslt/txXMLOutput.cpp index 9d4dd494a213..852632a288d5 100644 --- a/content/xslt/src/xslt/txXMLOutput.cpp +++ b/content/xslt/src/xslt/txXMLOutput.cpp @@ -47,13 +47,17 @@ txAttribute::txAttribute(PRInt32 aNsID, txAtom* aLocalName, const String& aValue { } -txXMLOutput::txXMLOutput() : mUseEmptyElementShorthand(MB_TRUE), - mHaveDocumentElement(MB_FALSE), - mStartTagOpen(MB_FALSE), - mAfterEndTag(MB_FALSE), - mInCDATASection(MB_FALSE), - mIndentLevel(0) +txXMLOutput::txXMLOutput(txOutputFormat* aFormat, ostream* aOut) + : mOut(aOut), + mUseEmptyElementShorthand(MB_TRUE), + mHaveDocumentElement(MB_FALSE), + mStartTagOpen(MB_FALSE), + mAfterEndTag(MB_FALSE), + mInCDATASection(MB_FALSE), + mIndentLevel(0) { + mOutputFormat.merge(*aFormat); + mOutputFormat.setFromDefaults(); } txXMLOutput::~txXMLOutput() @@ -251,24 +255,6 @@ void txXMLOutput::startElement(const String& aName, } } -void txXMLOutput::getOutputStream(ostream** aOutputStream) -{ - if (aOutputStream) - *aOutputStream = mOut; -} - -void txXMLOutput::setOutputStream(ostream* aOutputStream) -{ - mOut = aOutputStream; -} - -void txXMLOutput::setOutputFormat(txOutputFormat* aOutputFormat) -{ - mOutputFormat.reset(); - mOutputFormat.merge(*aOutputFormat); - mOutputFormat.setFromDefaults(); -} - void txXMLOutput::closeStartTag(MBool aUseEmptyElementShorthand) { mAfterEndTag = aUseEmptyElementShorthand; diff --git a/content/xslt/src/xslt/txXMLOutput.h b/content/xslt/src/xslt/txXMLOutput.h index 4aa9c9d1cad7..ac6f2acafb74 100644 --- a/content/xslt/src/xslt/txXMLOutput.h +++ b/content/xslt/src/xslt/txXMLOutput.h @@ -91,10 +91,10 @@ public: MBool mShorthand; }; -class txXMLOutput : public txStreamXMLEventHandler +class txXMLOutput : public txIOutputXMLEventHandler { public: - txXMLOutput(); + txXMLOutput(txOutputFormat* aFormat, ostream* aOut); virtual ~txXMLOutput(); static const int DEFAULT_INDENT; @@ -146,6 +146,18 @@ public: virtual void endElement(const String& aName, const PRInt32 aNsID); + /** + * Returns whether the output handler supports + * disable-output-escaping. + * + * @return MB_TRUE if this handler supports + * disable-output-escaping + */ + MBool hasDisableOutputEscaping() + { + return MB_TRUE; + } + /* * Signals to receive a processing instruction. * @@ -169,27 +181,6 @@ public: virtual void startElement(const String& aName, const PRInt32 aNsID); - /* - * Sets the output format. - * - * @param aOutputFormat the output format - */ - void setOutputFormat(txOutputFormat* aOutputFormat); - - /** - * Get the output stream. - * - * @param aOutputStream the current output stream - */ - void getOutputStream(ostream** aOutputStream); - - /** - * Sets the output stream. - * - * @param aOutputStream the new output stream - */ - void setOutputStream(ostream* aOutputStream); - protected: virtual void closeStartTag(MBool aUseEmptyElementShorthand); void printUTF8Char(DOM_CHAR& ch);