Back to index

lightning-sunbird  0.9+nobinonly
txStandaloneXSLTProcessor.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Peter Van der Beken <peterv@propagandism.org>
00024  *   Axel Hecht <axel@pike.org>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "txStandaloneXSLTProcessor.h"
00041 #include "txStandaloneStylesheetCompiler.h"
00042 #include "nsCRT.h"
00043 #include "nsReadableUtils.h"
00044 #include "txHTMLOutput.h"
00045 #include "txTextOutput.h"
00046 #include "txUnknownHandler.h"
00047 #include "txURIUtils.h"
00048 #include "txXMLParser.h"
00049 
00050 TX_IMPL_DOM_STATICS;
00051 
00055 class txStandaloneHandlerFactory : public txAOutputHandlerFactory
00056 {
00057 public:
00058     txStandaloneHandlerFactory(txExecutionState* aEs,
00059                                ostream* aStream)
00060         : mEs(aEs), mStream(aStream)
00061     {
00062     }
00063 
00064     virtual ~txStandaloneHandlerFactory()
00065     {
00066     };
00067 
00068     TX_DECL_TXAOUTPUTHANDLERFACTORY;
00069 
00070 private:
00071     txExecutionState* mEs;
00072     ostream* mStream;
00073 };
00074 
00075 nsresult
00076 txStandaloneHandlerFactory::createHandlerWith(txOutputFormat* aFormat,
00077                                               txAOutputXMLEventHandler** aHandler)
00078 {
00079     *aHandler = 0;
00080     switch (aFormat->mMethod) {
00081         case eXMLOutput:
00082             *aHandler = new txXMLOutput(aFormat, mStream);
00083             break;
00084 
00085         case eHTMLOutput:
00086             *aHandler = new txHTMLOutput(aFormat, mStream);
00087             break;
00088 
00089         case eTextOutput:
00090             *aHandler = new txTextOutput(mStream);
00091             break;
00092 
00093         case eMethodNotSet:
00094             *aHandler = new txUnknownHandler(mEs);
00095             break;
00096     }
00097     NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY);
00098     return NS_OK;
00099 }
00100 
00101 nsresult
00102 txStandaloneHandlerFactory::createHandlerWith(txOutputFormat* aFormat,
00103                                               const nsAString& aName,
00104                                               PRInt32 aNsID,
00105                                               txAOutputXMLEventHandler** aHandler)
00106 {
00107     *aHandler = 0;
00108     NS_ASSERTION(aFormat->mMethod != eMethodNotSet,
00109                  "How can method not be known when root element is?");
00110     NS_ENSURE_TRUE(aFormat->mMethod != eMethodNotSet, NS_ERROR_UNEXPECTED);
00111     return createHandlerWith(aFormat, aHandler);
00112 }
00113 
00114 
00124 nsresult
00125 txStandaloneXSLTProcessor::transform(nsACString& aXMLPath, ostream& aOut,
00126                                      ErrorObserver& aErr)
00127 {
00128     txXPathNode* xmlDoc = parsePath(aXMLPath, aErr);
00129     if (!xmlDoc) {
00130         return NS_ERROR_FAILURE;
00131     }
00132 
00133     // transform
00134     nsresult rv = transform(*xmlDoc, aOut, aErr);
00135 
00136     delete xmlDoc;
00137 
00138     return rv;
00139 }
00140 
00145 nsresult
00146 txStandaloneXSLTProcessor::transform(nsACString& aXMLPath,
00147                                      nsACString& aXSLPath, ostream& aOut,
00148                                      ErrorObserver& aErr)
00149 {
00150     txXPathNode* xmlDoc = parsePath(aXMLPath, aErr);
00151     if (!xmlDoc) {
00152         return NS_ERROR_FAILURE;
00153     }
00154     txParsedURL path;
00155     path.init(NS_ConvertASCIItoUCS2(aXSLPath));
00156     nsRefPtr<txStylesheet> style;
00157     nsresult rv = TX_CompileStylesheetPath(path, getter_AddRefs(style));
00158     if (NS_FAILED(rv)) {
00159         delete xmlDoc;
00160         return rv;
00161     }
00162     // transform
00163     rv = transform(*xmlDoc, style, aOut, aErr);
00164 
00165     delete xmlDoc;
00166 
00167     return rv;
00168 }
00169 
00175 nsresult
00176 txStandaloneXSLTProcessor::transform(txXPathNode& aXMLDoc, ostream& aOut,
00177                                      ErrorObserver& aErr)
00178 {
00179     Document* xmlDoc;
00180     nsresult rv = txXPathNativeNode::getDocument(aXMLDoc, &xmlDoc);
00181     NS_ENSURE_SUCCESS(rv, rv);
00182 
00183     // get stylesheet path
00184     nsAutoString stylePath, basePath;
00185     xmlDoc->getBaseURI(basePath);
00186     getHrefFromStylesheetPI(*xmlDoc, stylePath);
00187     txParsedURL base, ref, resolved;
00188     base.init(basePath);
00189     ref.init(stylePath);
00190     base.resolve(ref, resolved);
00191 
00192     nsRefPtr<txStylesheet> style;
00193     rv = TX_CompileStylesheetPath(resolved, getter_AddRefs(style));
00194     NS_ENSURE_SUCCESS(rv, rv);
00195 
00196     // transform
00197     rv = transform(aXMLDoc, style, aOut, aErr);
00198 
00199     return rv;
00200 }
00201 
00206 nsresult
00207 txStandaloneXSLTProcessor::transform(txXPathNode& aSource,
00208                                      txStylesheet* aStylesheet,
00209                                      ostream& aOut, ErrorObserver& aErr)
00210 {
00211     // Create a new txEvalState
00212     txExecutionState es(aStylesheet);
00213 
00214     // XXX todo es.addErrorObserver(aErr);
00215 
00216     txStandaloneHandlerFactory handlerFactory(&es, &aOut);
00217 
00218 #ifndef XP_WIN
00219     bool sync = aOut.sync_with_stdio(false);
00220 #endif
00221     es.mOutputHandlerFactory = &handlerFactory;
00222 
00223     es.init(aSource, nsnull);
00224 
00225     // Process root of XML source document
00226     nsresult rv = txXSLTProcessor::execute(es);
00227     es.end(rv);
00228 
00229 #ifndef XP_WIN
00230     aOut.sync_with_stdio(sync);
00231 #endif
00232 
00233     return rv;
00234 }
00235 
00243 void txStandaloneXSLTProcessor::getHrefFromStylesheetPI(Document& xmlDocument,
00244                                                         nsAString& href)
00245 {
00246     Node* node = xmlDocument.getFirstChild();
00247     nsAutoString type;
00248     nsAutoString tmpHref;
00249     while (node) {
00250         if (node->getNodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
00251             nsAutoString target;
00252             node->getNodeName(target);
00253             if (target.EqualsLiteral("xml-stylesheet")) {
00254                 nsAutoString data;
00255                 node->getNodeValue(data);
00256                 type.Truncate();
00257                 tmpHref.Truncate();
00258                 parseStylesheetPI(data, type, tmpHref);
00259                 if (type.EqualsLiteral("text/xsl") ||
00260                     type.EqualsLiteral("text/xml") ||
00261                     type.EqualsLiteral("application/xml")) {
00262                     href = tmpHref;
00263                     return;
00264                 }
00265             }
00266         }
00267         node = node->getNextSibling();
00268     }
00269 }
00270 
00275 #define SKIP_WHITESPACE(iter, end_iter)                          \
00276   while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \
00277     ++(iter);                                                    \
00278   }                                                              \
00279   if ((iter) == (end_iter))                                      \
00280     break
00281 
00282 #define SKIP_ATTR_NAME(iter, end_iter)                            \
00283   while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \
00284          *(iter) != '=') {                                        \
00285     ++(iter);                                                     \
00286   }                                                               \
00287   if ((iter) == (end_iter))                                       \
00288     break
00289 
00290 void txStandaloneXSLTProcessor::parseStylesheetPI(const nsAFlatString& aData,
00291                                                   nsAString& aType,
00292                                                   nsAString& aHref)
00293 {
00294   nsAFlatString::const_char_iterator start, end;
00295   aData.BeginReading(start);
00296   aData.EndReading(end);
00297   nsAFlatString::const_char_iterator iter;
00298   PRInt8 found = 0;
00299 
00300   while (start != end) {
00301     SKIP_WHITESPACE(start, end);
00302     iter = start;
00303     SKIP_ATTR_NAME(iter, end);
00304 
00305     // Remember the attr name.
00306     const nsAString & attrName = Substring(start, iter);
00307 
00308     // Now check whether this is a valid name="value" pair.
00309     start = iter;
00310     SKIP_WHITESPACE(start, end);
00311     if (*start != '=') {
00312       // No '=', so this is not a name="value" pair.  We don't know
00313       // what it is, and we have no way to handle it.
00314       break;
00315     }
00316 
00317     // Have to skip the value.
00318     ++start;
00319     SKIP_WHITESPACE(start, end);
00320     PRUnichar q = *start;
00321     if (q != QUOTE && q != APOSTROPHE) {
00322       // Not a valid quoted value, so bail.
00323       break;
00324     }
00325 
00326     ++start;  // Point to the first char of the value.
00327     iter = start;
00328     while (iter != end && *iter != q) {
00329       ++iter;
00330     }
00331     if (iter == end) {
00332       // Oops, unterminated quoted string.
00333       break;
00334     }
00335     
00336     // At this point attrName holds the name of the "attribute" and
00337     // the value is between start and iter.
00338     if (attrName.EqualsLiteral("type")) {
00339       aType = Substring(start, iter);
00340       ++found;
00341     }
00342     else if (attrName.EqualsLiteral("href")) {
00343       aHref = Substring(start, iter);
00344       ++found;
00345     }
00346 
00347     // Stop if we found both attributes
00348     if (found == 2) {
00349       break;
00350     }
00351 
00352     // Resume scanning after the end of the attribute value.
00353     start = iter;
00354     ++start;  // To move past the quote char.
00355   }
00356 }
00357 
00358 txXPathNode*
00359 txStandaloneXSLTProcessor::parsePath(const nsACString& aPath, ErrorObserver& aErr)
00360 {
00361     NS_ConvertASCIItoUCS2 path(aPath);
00362 
00363     ifstream xmlInput(PromiseFlatCString(aPath).get(), ios::in);
00364     if (!xmlInput) {
00365         aErr.receiveError(NS_LITERAL_STRING("Couldn't open ") + path);
00366         return 0;
00367     }
00368     // parse source
00369     txXPathNode* xmlDoc;
00370     nsAutoString errors;
00371     nsresult rv = txParseFromStream(xmlInput, path, errors, &xmlDoc);
00372     xmlInput.close();
00373     if (NS_FAILED(rv) || !xmlDoc) {
00374         aErr.receiveError(NS_LITERAL_STRING("Parsing error \"") + errors +
00375                           NS_LITERAL_STRING("\""));
00376     }
00377     return xmlDoc;
00378 }