Home | History | Annotate | Download | only in xml
      1 /*
      2  * This file is part of the XSL implementation.
      3  *
      4  * Copyright (C) 2009 Jakub Wieczorek <faw217 (at) gmail.com>
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Library General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Library General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Library General Public License
     17  * along with this library; see the file COPYING.LIB.  If not, write to
     18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19  * Boston, MA 02110-1301, USA.
     20  */
     21 
     22 #include "config.h"
     23 
     24 #if ENABLE(XSLT)
     25 
     26 #include "XSLTProcessor.h"
     27 
     28 #include "Console.h"
     29 #include "DOMWindow.h"
     30 #include "Frame.h"
     31 #include "TransformSource.h"
     32 #include "markup.h"
     33 #include <wtf/Assertions.h>
     34 #include <wtf/Vector.h>
     35 
     36 #include <qabstractmessagehandler.h>
     37 #include <qabstracturiresolver.h>
     38 #include <qbuffer.h>
     39 #include <qsourcelocation.h>
     40 #include <qxmlquery.h>
     41 
     42 namespace WebCore {
     43 
     44 class XSLTMessageHandler : public QAbstractMessageHandler {
     45 
     46 public:
     47     XSLTMessageHandler(Document* document = 0);
     48     virtual void handleMessage(QtMsgType type, const QString& description,
     49                                const QUrl& identifier, const QSourceLocation& sourceLocation);
     50 
     51 private:
     52     Document* m_document;
     53 };
     54 
     55 XSLTMessageHandler::XSLTMessageHandler(Document* document)
     56     : QAbstractMessageHandler()
     57     , m_document(document)
     58 {
     59 }
     60 
     61 void XSLTMessageHandler::handleMessage(QtMsgType type, const QString& description,
     62                                        const QUrl&, const QSourceLocation& sourceLocation)
     63 {
     64     if (!m_document->frame())
     65         return;
     66 
     67     MessageLevel level;
     68     switch (type) {
     69     case QtDebugMsg:
     70         level = TipMessageLevel;
     71         break;
     72     case QtWarningMsg:
     73         level = WarningMessageLevel;
     74         break;
     75     case QtCriticalMsg:
     76     case QtFatalMsg:
     77         level = ErrorMessageLevel;
     78         break;
     79     default:
     80         level = LogMessageLevel;
     81         break;
     82     }
     83 
     84     Console* console = m_document->frame()->domWindow()->console();
     85     console->addMessage(XMLMessageSource, LogMessageType, level, description,
     86                         sourceLocation.line(), sourceLocation.uri().toString());
     87 }
     88 
     89 class XSLTUriResolver : public QAbstractUriResolver {
     90 
     91 public:
     92     XSLTUriResolver(Document* document);
     93     virtual QUrl resolve(const QUrl& relative, const QUrl& baseURI) const;
     94 
     95 private:
     96     Document* m_document;
     97 };
     98 
     99 XSLTUriResolver::XSLTUriResolver(Document* document)
    100     : QAbstractUriResolver()
    101     , m_document(document)
    102 {
    103 }
    104 
    105 QUrl XSLTUriResolver::resolve(const QUrl& relative, const QUrl& baseURI) const
    106 {
    107     QUrl url = baseURI.resolved(relative);
    108 
    109     if (!m_document->frame() || !m_document->securityOrigin()->canRequest(url))
    110         return QUrl();
    111     return url;
    112 }
    113 
    114 bool XSLTProcessor::transformToString(Node* sourceNode, String&, String& resultString, String&)
    115 {
    116     bool success = false;
    117 
    118     RefPtr<XSLStyleSheet> stylesheet = m_stylesheet;
    119     if (!stylesheet && m_stylesheetRootNode) {
    120         Node* node = m_stylesheetRootNode.get();
    121         stylesheet = XSLStyleSheet::createForXSLTProcessor(node->parentNode() ? node->parentNode() : node,
    122             node->document()->url().string(),
    123             node->document()->url()); // FIXME: Should we use baseURL here?
    124 
    125         // According to Mozilla documentation, the node must be a Document node, an xsl:stylesheet or xsl:transform element.
    126         // But we just use text content regardless of node type.
    127         stylesheet->parseString(createMarkup(node));
    128     }
    129 
    130     if (!stylesheet || stylesheet->sheetString().isEmpty())
    131         return success;
    132 
    133     RefPtr<Document> ownerDocument = sourceNode->document();
    134     bool sourceIsDocument = (sourceNode == ownerDocument.get());
    135 
    136     QXmlQuery query(QXmlQuery::XSLT20);
    137 
    138     XSLTMessageHandler messageHandler(ownerDocument.get());
    139     XSLTUriResolver uriResolver(ownerDocument.get());
    140     query.setMessageHandler(&messageHandler);
    141 
    142     XSLTProcessor::ParameterMap::iterator end = m_parameters.end();
    143     for (XSLTProcessor::ParameterMap::iterator it = m_parameters.begin(); it != end; ++it)
    144         query.bindVariable(QString(it->first), QXmlItem(QVariant(QString(it->second))));
    145 
    146     QString source;
    147     if (sourceIsDocument && ownerDocument->transformSource())
    148         source = ownerDocument->transformSource()->platformSource();
    149     if (!sourceIsDocument || source.isEmpty())
    150         source = createMarkup(sourceNode);
    151 
    152     QBuffer inputBuffer;
    153     QBuffer styleSheetBuffer;
    154     QBuffer outputBuffer;
    155 
    156     inputBuffer.setData(source.toUtf8());
    157     styleSheetBuffer.setData(QString(stylesheet->sheetString()).toUtf8());
    158 
    159     inputBuffer.open(QIODevice::ReadOnly);
    160     styleSheetBuffer.open(QIODevice::ReadOnly);
    161     outputBuffer.open(QIODevice::ReadWrite);
    162 
    163     query.setFocus(&inputBuffer);
    164     query.setQuery(&styleSheetBuffer, QUrl(stylesheet->href()));
    165 
    166     query.setUriResolver(&uriResolver);
    167 
    168     success = query.evaluateTo(&outputBuffer);
    169     outputBuffer.reset();
    170     resultString = QString::fromUtf8(outputBuffer.readAll()).trimmed();
    171 
    172     if (m_stylesheet) {
    173         m_stylesheet->clearDocuments();
    174         m_stylesheet = 0;
    175     }
    176 
    177     return success;
    178 }
    179 
    180 } // namespace WebCore
    181 
    182 #endif // ENABLE(XSLT)
    183