1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Mozilla Public License Version
6
* 1.1 (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/MPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is mozilla.org code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 2002
20
* the Initial Developer. All Rights Reserved.
23
* Peter Van der Beken <peterv@netscape.com> (original author)
24
* Axel Hecht <axel@pike.org>
27
* Alternatively, the contents of this file may be used under the terms of
28
* either the GNU General Public License Version 2 or later (the "GPL"), or
29
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30
* in which case the provisions of the GPL or the LGPL are applicable instead
31
* of those above. If you wish to allow use of your version of this file only
32
* under the terms of either the GPL or the LGPL, and not to allow others to
33
* use your version of this file under the terms of the MPL, indicate your
34
* decision by deleting the provisions above and replace them with the notice
35
* and other provisions required by the GPL or the LGPL. If you do not delete
36
* the provisions above, a recipient may use your version of this file under
37
* the terms of any one of the MPL, the GPL or the LGPL.
39
* ***** END LICENSE BLOCK ***** */
41
#include "txStandaloneXSLTProcessor.h"
42
#include "txStandaloneStylesheetCompiler.h"
44
#include "nsReadableUtils.h"
45
#include "txHTMLOutput.h"
46
#include "txTextOutput.h"
47
#include "txUnknownHandler.h"
48
#include "txURIUtils.h"
49
#include "txXMLParser.h"
54
* Output Handler Factory
56
class txStandaloneHandlerFactory : public txAOutputHandlerFactory
59
txStandaloneHandlerFactory(txExecutionState* aEs,
61
: mEs(aEs), mStream(aStream)
65
virtual ~txStandaloneHandlerFactory()
69
TX_DECL_TXAOUTPUTHANDLERFACTORY;
72
txExecutionState* mEs;
77
txStandaloneHandlerFactory::createHandlerWith(txOutputFormat* aFormat,
78
txAOutputXMLEventHandler** aHandler)
81
switch (aFormat->mMethod) {
83
*aHandler = new txXMLOutput(aFormat, mStream);
87
*aHandler = new txHTMLOutput(aFormat, mStream);
91
*aHandler = new txTextOutput(mStream);
95
*aHandler = new txUnknownHandler(mEs);
98
NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY);
103
txStandaloneHandlerFactory::createHandlerWith(txOutputFormat* aFormat,
104
const nsAString& aName,
106
txAOutputXMLEventHandler** aHandler)
109
NS_ASSERTION(aFormat->mMethod != eMethodNotSet,
110
"How can method not be known when root element is?");
111
NS_ENSURE_TRUE(aFormat->mMethod != eMethodNotSet, NS_ERROR_UNEXPECTED);
112
return createHandlerWith(aFormat, aHandler);
117
* txStandaloneXSLTProcessor
121
* Transform a XML document given by path.
122
* The stylesheet is retrieved by a processing instruction,
123
* or an error is returned.
126
txStandaloneXSLTProcessor::transform(nsACString& aXMLPath, ostream& aOut,
129
txXPathNode* xmlDoc = parsePath(aXMLPath, aErr);
131
return NS_ERROR_FAILURE;
135
nsresult rv = transform(*xmlDoc, aOut, aErr);
143
* Transform a XML document given by path with the given
147
txStandaloneXSLTProcessor::transform(nsACString& aXMLPath,
148
nsACString& aXSLPath, ostream& aOut,
151
txXPathNode* xmlDoc = parsePath(aXMLPath, aErr);
153
return NS_ERROR_FAILURE;
156
path.init(NS_ConvertASCIItoUCS2(aXSLPath));
157
nsRefPtr<txStylesheet> style;
158
nsresult rv = TX_CompileStylesheetPath(path, getter_AddRefs(style));
164
rv = transform(*xmlDoc, style, aOut, aErr);
172
* Transform a XML document.
173
* The stylesheet is retrieved by a processing instruction,
174
* or an error is returned.
177
txStandaloneXSLTProcessor::transform(txXPathNode& aXMLDoc, ostream& aOut,
181
nsresult rv = txXPathNativeNode::getDocument(aXMLDoc, &xmlDoc);
182
NS_ENSURE_SUCCESS(rv, rv);
184
// get stylesheet path
185
nsAutoString stylePath, basePath;
186
xmlDoc->getBaseURI(basePath);
187
getHrefFromStylesheetPI(*xmlDoc, stylePath);
188
txParsedURL base, ref, resolved;
191
base.resolve(ref, resolved);
193
nsRefPtr<txStylesheet> style;
194
rv = TX_CompileStylesheetPath(resolved, getter_AddRefs(style));
195
NS_ENSURE_SUCCESS(rv, rv);
198
rv = transform(aXMLDoc, style, aOut, aErr);
204
* Processes the given XML Document using the given XSL document
205
* and prints the results to the given ostream argument
208
txStandaloneXSLTProcessor::transform(txXPathNode& aSource,
209
txStylesheet* aStylesheet,
210
ostream& aOut, ErrorObserver& aErr)
212
// Create a new txEvalState
213
txExecutionState es(aStylesheet);
215
// XXX todo es.addErrorObserver(aErr);
217
txStandaloneHandlerFactory handlerFactory(&es, &aOut);
220
bool sync = aOut.sync_with_stdio(false);
222
es.mOutputHandlerFactory = &handlerFactory;
224
es.init(aSource, nsnull);
226
// Process root of XML source document
227
nsresult rv = txXSLTProcessor::execute(es);
231
aOut.sync_with_stdio(sync);
238
* Parses the XML Stylesheet PIs associated with the
239
* given XML document. If a stylesheet PIs is found with type="text/xsl"
240
* or type="text/xml" the href psuedo attribute value will be appended to
241
* the given href argument. If multiple text/xsl stylesheet PIs
242
* are found, the first one is used.
244
void txStandaloneXSLTProcessor::getHrefFromStylesheetPI(Document& xmlDocument,
247
Node* node = xmlDocument.getFirstChild();
249
nsAutoString tmpHref;
251
if (node->getNodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
253
node->getNodeName(target);
254
if (target.Equals(NS_LITERAL_STRING("xml-stylesheet"))) {
256
node->getNodeValue(data);
259
parseStylesheetPI(data, type, tmpHref);
260
if (type.Equals(NS_LITERAL_STRING("text/xsl")) ||
261
type.Equals(NS_LITERAL_STRING("text/xml"))) {
267
node = node->getNextSibling();
272
* Parses the contents of data, and returns the type and href pseudo attributes
273
* (Based on code copied from nsParserUtils)
275
#define SKIP_WHITESPACE(iter, end_iter) \
276
while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \
279
if ((iter) == (end_iter)) \
282
#define SKIP_ATTR_NAME(iter, end_iter) \
283
while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \
287
if ((iter) == (end_iter)) \
290
void txStandaloneXSLTProcessor::parseStylesheetPI(const nsAFlatString& aData,
294
nsAFlatString::const_char_iterator start, end;
295
aData.BeginReading(start);
296
aData.EndReading(end);
297
nsAFlatString::const_char_iterator iter;
300
while (start != end) {
301
SKIP_WHITESPACE(start, end);
303
SKIP_ATTR_NAME(iter, end);
305
// Remember the attr name.
306
const nsAString & attrName = Substring(start, iter);
308
// Now check whether this is a valid name="value" pair.
310
SKIP_WHITESPACE(start, end);
312
// No '=', so this is not a name="value" pair. We don't know
313
// what it is, and we have no way to handle it.
317
// Have to skip the value.
319
SKIP_WHITESPACE(start, end);
320
PRUnichar q = *start;
321
if (q != QUOTE && q != APOSTROPHE) {
322
// Not a valid quoted value, so bail.
326
++start; // Point to the first char of the value.
328
while (iter != end && *iter != q) {
332
// Oops, unterminated quoted string.
336
// At this point attrName holds the name of the "attribute" and
337
// the value is between start and iter.
338
if (attrName.Equals(NS_LITERAL_STRING("type"))) {
339
aType = Substring(start, iter);
342
else if (attrName.Equals(NS_LITERAL_STRING("href"))) {
343
aHref = Substring(start, iter);
347
// Stop if we found both attributes
352
// Resume scanning after the end of the attribute value.
354
++start; // To move past the quote char.
359
txStandaloneXSLTProcessor::parsePath(const nsACString& aPath, ErrorObserver& aErr)
361
NS_ConvertASCIItoUCS2 path(aPath);
363
ifstream xmlInput(PromiseFlatCString(aPath).get(), ios::in);
365
aErr.receiveError(NS_LITERAL_STRING("Couldn't open ") + path);
371
nsresult rv = txParseFromStream(xmlInput, path, errors, &xmlDoc);
373
if (NS_FAILED(rv) || !xmlDoc) {
374
aErr.receiveError(NS_LITERAL_STRING("Parsing error \"") + errors +
375
NS_LITERAL_STRING("\""));