📄 xmltokenizerqt.cpp
字号:
/* * Copyright (C) 2000 Peter Kelly (pmk@post.com) * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved. * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) * Copyright (C) 2007 Samuel Weinig (sam@webkit.org) * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2008 Holger Hans Peter Freyther * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */#include "config.h"#include "XMLTokenizer.h"#include "CDATASection.h"#include "CString.h"#include "CachedScript.h"#include "Comment.h"#include "DocLoader.h"#include "Document.h"#include "DocumentFragment.h"#include "DocumentType.h"#include "Frame.h"#include "FrameLoader.h"#include "FrameView.h"#include "HTMLLinkElement.h"#include "HTMLStyleElement.h"#include "HTMLTokenizer.h"#include "ProcessingInstruction.h"#include "ResourceError.h"#include "ResourceHandle.h"#include "ResourceRequest.h"#include "ResourceResponse.h"#include "ScriptController.h"#include "ScriptElement.h"#include "ScriptSourceCode.h"#include "ScriptValue.h"#include "TextResourceDecoder.h"#include <QDebug>#include <wtf/Platform.h>#include <wtf/StringExtras.h>#include <wtf/Threading.h>#include <wtf/Vector.h>using namespace std;namespace WebCore {#if QT_VERSION >= 0x040400class EntityResolver : public QXmlStreamEntityResolver{ virtual QString resolveUndeclaredEntity(const QString &name);};QString EntityResolver::resolveUndeclaredEntity(const QString &name){ UChar c = decodeNamedEntity(name.toUtf8().constData()); return QString(c);}#endif// --------------------------------XMLTokenizer::XMLTokenizer(Document* _doc, FrameView* _view) : m_doc(_doc) , m_view(_view) , m_wroteText(false) , m_currentNode(_doc) , m_currentNodeIsReferenced(false) , m_sawError(false) , m_sawXSLTransform(false) , m_sawFirstElement(false) , m_isXHTMLDocument(false) , m_parserPaused(false) , m_requestingScript(false) , m_finishCalled(false) , m_errorCount(0) , m_lastErrorLine(0) , m_lastErrorColumn(0) , m_pendingScript(0) , m_scriptStartLine(0) , m_parsingFragment(false){#if QT_VERSION >= 0x040400 m_stream.setEntityResolver(new EntityResolver);#endif}XMLTokenizer::XMLTokenizer(DocumentFragment* fragment, Element* parentElement) : m_doc(fragment->document()) , m_view(0) , m_wroteText(false) , m_currentNode(fragment) , m_currentNodeIsReferenced(fragment) , m_sawError(false) , m_sawXSLTransform(false) , m_sawFirstElement(false) , m_isXHTMLDocument(false) , m_parserPaused(false) , m_requestingScript(false) , m_finishCalled(false) , m_errorCount(0) , m_lastErrorLine(0) , m_lastErrorColumn(0) , m_pendingScript(0) , m_scriptStartLine(0) , m_parsingFragment(true){ if (fragment) fragment->ref(); if (m_doc) m_doc->ref(); // Add namespaces based on the parent node Vector<Element*> elemStack; while (parentElement) { elemStack.append(parentElement); Node* n = parentElement->parentNode(); if (!n || !n->isElementNode()) break; parentElement = static_cast<Element*>(n); } if (elemStack.isEmpty()) return; #if QT_VERSION < 0x040400 for (Element* element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) { if (NamedAttrMap* attrs = element->attributes()) { for (unsigned i = 0; i < attrs->length(); i++) { Attribute* attr = attrs->attributeItem(i); if (attr->localName() == "xmlns") m_defaultNamespaceURI = attr->value(); else if (attr->prefix() == "xmlns") m_prefixToNamespaceMap.set(attr->localName(), attr->value()); } } }#else QXmlStreamNamespaceDeclarations namespaces; for (Element* element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) { if (NamedAttrMap* attrs = element->attributes()) { for (unsigned i = 0; i < attrs->length(); i++) { Attribute* attr = attrs->attributeItem(i); if (attr->localName() == "xmlns") m_defaultNamespaceURI = attr->value(); else if (attr->prefix() == "xmlns") namespaces.append(QXmlStreamNamespaceDeclaration(attr->localName(), attr->value())); } } } m_stream.addExtraNamespaceDeclarations(namespaces); m_stream.setEntityResolver(new EntityResolver);#endif // If the parent element is not in document tree, there may be no xmlns attribute; just default to the parent's namespace. if (m_defaultNamespaceURI.isNull() && !parentElement->inDocument()) m_defaultNamespaceURI = parentElement->namespaceURI();}XMLTokenizer::~XMLTokenizer(){ setCurrentNode(0); if (m_parsingFragment && m_doc) m_doc->deref(); if (m_pendingScript) m_pendingScript->removeClient(this);#if QT_VERSION >= 0x040400 delete m_stream.entityResolver();#endif}void XMLTokenizer::doWrite(const String& parseString){ m_wroteText = true; if (m_doc->decoder() && m_doc->decoder()->sawError()) { // If the decoder saw an error, report it as fatal (stops parsing) handleError(fatal, "Encoding error", lineNumber(), columnNumber()); return; } QString data(parseString); if (!data.isEmpty()) {#if QT_VERSION < 0x040400 if (!m_sawFirstElement) { int idx = data.indexOf(QLatin1String("<?xml")); if (idx != -1) { int start = idx + 5; int end = data.indexOf(QLatin1String("?>"), start); QString content = data.mid(start, end-start); bool ok = true; HashMap<String, String> attrs = parseAttributes(content, ok); String version = attrs.get("version"); String encoding = attrs.get("encoding"); ExceptionCode ec = 0; if (!m_parsingFragment) { if (!version.isEmpty()) m_doc->setXMLVersion(version, ec); if (!encoding.isEmpty()) m_doc->setXMLEncoding(encoding); } } }#endif m_stream.addData(data); parse(); } return;}void XMLTokenizer::initializeParserContext(const char* chunk){ m_parserStopped = false; m_sawError = false; m_sawXSLTransform = false; m_sawFirstElement = false;}void XMLTokenizer::doEnd(){#if ENABLE(XSLT) #warning Look at XMLTokenizerLibXml.cpp#endif if (m_stream.error() == QXmlStreamReader::PrematureEndOfDocumentError || (m_wroteText && !m_sawFirstElement)) { handleError(fatal, qPrintable(m_stream.errorString()), lineNumber(), columnNumber()); }}#if ENABLE(XSLT)void* xmlDocPtrForString(DocLoader* docLoader, const String& source, const String& url){ if (source.isEmpty()) return 0; // Parse in a single chunk into an xmlDocPtr // FIXME: Hook up error handlers so that a failure to parse the main document results in // good error messages. const UChar BOM = 0xFEFF; const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM); xmlGenericErrorFunc oldErrorFunc = xmlGenericError; void* oldErrorContext = xmlGenericErrorContext; setLoaderForLibXMLCallbacks(docLoader); xmlSetGenericErrorFunc(0, errorFunc); xmlDocPtr sourceDoc = xmlReadMemory(reinterpret_cast<const char*>(source.characters()), source.length() * sizeof(UChar), url.latin1().data(), BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE", XSLT_PARSE_OPTIONS); setLoaderForLibXMLCallbacks(0); xmlSetGenericErrorFunc(oldErrorContext, oldErrorFunc); return sourceDoc;}#endifint XMLTokenizer::lineNumber() const{ return m_stream.lineNumber();}int XMLTokenizer::columnNumber() const{ return m_stream.columnNumber();}void XMLTokenizer::stopParsing(){ Tokenizer::stopParsing();}void XMLTokenizer::resumeParsing(){ ASSERT(m_parserPaused); m_parserPaused = false; // First, execute any pending callbacks parse(); if (m_parserPaused) return; // Then, write any pending data SegmentedString rest = m_pendingSrc; m_pendingSrc.clear(); write(rest, false); // Finally, if finish() has been called and write() didn't result // in any further callbacks being queued, call end() if (m_finishCalled && !m_parserPaused && !m_pendingScript) end();}bool parseXMLDocumentFragment(const String& chunk, DocumentFragment* fragment, Element* parent){ if (!chunk.length()) return true; XMLTokenizer tokenizer(fragment, parent); tokenizer.write(String("<qxmlstreamdummyelement>"), false); tokenizer.write(chunk, false); tokenizer.write(String("</qxmlstreamdummyelement>"), false); tokenizer.finish(); return !tokenizer.hasError();}// --------------------------------struct AttributeParseState { HashMap<String, String> attributes; bool gotAttributes;};static void attributesStartElementNsHandler(AttributeParseState* state, const QXmlStreamAttributes& attrs){ if (attrs.count() <= 0) return; state->gotAttributes = true; for(int i = 0; i < attrs.count(); i++) { const QXmlStreamAttribute& attr = attrs[i]; String attrLocalName = attr.name(); String attrValue = attr.value(); String attrURI = attr.namespaceUri(); String attrQName = attr.qualifiedName(); state->attributes.set(attrQName, attrValue); }}HashMap<String, String> parseAttributes(const String& string, bool& attrsOK){ AttributeParseState state; state.gotAttributes = false; QXmlStreamReader stream; QString dummy = QString(QLatin1String("<?xml version=\"1.0\"?><attrs %1 />")).arg(string); stream.addData(dummy); while (!stream.atEnd()) { stream.readNext(); if (stream.isStartElement()) { attributesStartElementNsHandler(&state, stream.attributes()); } } attrsOK = state.gotAttributes; return state.attributes;}static inline String prefixFromQName(const QString& qName){ const int offset = qName.indexOf(QLatin1Char(':')); if (offset <= 0) return String(); else return qName.left(offset);}static inline void handleElementNamespaces(Element* newElement, const QXmlStreamNamespaceDeclarations &ns, ExceptionCode& ec){ for (int i = 0; i < ns.count(); ++i) { const QXmlStreamNamespaceDeclaration &decl = ns[i]; String namespaceURI = decl.namespaceUri(); String namespaceQName = decl.prefix().isEmpty() ? String("xmlns") : String("xmlns:") + decl.prefix(); newElement->setAttributeNS("http://www.w3.org/2000/xmlns/", namespaceQName, namespaceURI, ec);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -