📄 xml_tokenizer.cpp
字号:
}
if (m_currentNode->addChild(newElement)) {
if (m_view && !newElement->attached())
newElement->attach();
m_currentNode = newElement;
return;
}
else {
delete newElement;
return;
}
// ### DOM spec states: "if there is no markup inside an element's content, the text is contained in a
// single object implementing the Text interface that is the only child of the element."... do we
// need to ensure that empty elements always have an empty text child?
}
void XMLTokenizer::endElement()
{
if (m_parserStopped) return;
popNamespaces();
if (m_currentNode->nodeType() == Node::TEXT_NODE)
exitText();
if (m_currentNode->parentNode() != 0) {
do {
m_currentNode = m_currentNode->parentNode();
} while (m_currentNode && m_currentNode->implicitNode());
}
// ### else error
}
void XMLTokenizer::characters(const xmlChar *s, int len)
{
if (m_parserStopped) return;
if (m_currentNode->nodeType() == Node::TEXT_NODE ||
m_currentNode->nodeType() == Node::CDATA_SECTION_NODE ||
enterText()) {
int exceptioncode = 0;
static_cast<TextImpl*>(m_currentNode)->appendData(QString::fromUtf8(reinterpret_cast<const char *>(s), len),
exceptioncode);
}
}
bool XMLTokenizer::enterText()
{
NodeImpl *newNode = m_doc->document()->createTextNode("");
if (m_currentNode->addChild(newNode)) {
m_currentNode = newNode;
return true;
}
else {
delete newNode;
return false;
}
}
void XMLTokenizer::exitText()
{
if (m_view && m_currentNode && !m_currentNode->attached())
m_currentNode->attach();
NodeImpl* par = m_currentNode->parentNode();
if (par != 0)
m_currentNode = par;
}
void XMLTokenizer::error(ErrorType type, const char *message, va_list args)
{
if (m_parserStopped) {
return;
}
if (type == fatal || (m_errorCount < maxErrors && m_lastErrorLine != lineNumber() && m_lastErrorColumn != columnNumber())) {
QString format;
switch (type) {
case warning:
#if APPLE_CHANGES
format = QString("warning on line %2 at column %3: %1");
#else
format = i18n( "warning: %1 in line %2, column %3\n" );
#endif
break;
case fatal:
#if APPLE_CHANGES
// fall through
#else
format = i18n( "fatal error: %1 in line %2, column %3\n" );
break;
#endif
default:
#if APPLE_CHANGES
format = QString("error on line %2 at column %3: %1");
#else
format = i18n( "error: %1 in line %2, column %3\n" );
#endif
}
#if !NOKIA_CHANGES
char *m;
vasprintf(&m, message, args);
m_errorMessages += format.arg(m).arg(lineNumber()).arg(columnNumber());
free(m);
#endif
m_lastErrorLine = lineNumber();
m_lastErrorColumn = columnNumber();
++m_errorCount;
}
if (type != warning)
m_sawError = true;
if (type == fatal)
stopParsing();
}
void XMLTokenizer::processingInstruction(const xmlChar *target, const xmlChar *data)
{
if (m_parserStopped) {
return;
}
if (m_currentNode->nodeType() == Node::TEXT_NODE)
exitText();
// ### handle exceptions
ProcessingInstructionImpl *pi = m_doc->document()->createProcessingInstruction(
QString::fromUtf8(reinterpret_cast<const char *>(target)),
QString::fromUtf8(reinterpret_cast<const char *>(data)));
m_currentNode->addChild(pi);
// don't load stylesheets for standalone documents
if (m_doc->document()->part()) {
m_sawXSLTransform = !pi->checkStyleSheet();
if (m_sawXSLTransform)
// Stop the SAX parser.
stopParsing();
}
}
void XMLTokenizer::cdataBlock(const xmlChar *s, int len)
{
if (m_parserStopped) {
return;
}
if (m_currentNode->nodeType() == Node::TEXT_NODE)
exitText();
NodeImpl *newNode = m_doc->document()->createCDATASection("");
if (m_currentNode->addChild(newNode)) {
if (m_view && !newNode->attached())
newNode->attach();
m_currentNode = newNode;
}
else {
delete newNode;
return;
}
characters(s, len);
if (m_currentNode->parentNode() != 0)
m_currentNode = m_currentNode->parentNode();
}
void XMLTokenizer::comment(const xmlChar *s)
{
if (m_parserStopped) return;
if (m_currentNode->nodeType() == Node::TEXT_NODE)
exitText();
// ### handle exceptions
m_currentNode->addChild(m_doc->document()->createComment(QString::fromUtf8(reinterpret_cast<const char *>(s))));
}
static void startElementHandler(void *userData, const xmlChar *name, const xmlChar **libxmlAttributes)
{
static_cast<XMLTokenizer *>(userData)->startElement(name, libxmlAttributes);
}
static void endElementHandler(void *userData, const xmlChar *name)
{
static_cast<XMLTokenizer *>(userData)->endElement();
}
static void charactersHandler(void *userData, const xmlChar *s, int len)
{
static_cast<XMLTokenizer *>(userData)->characters(s, len);
}
static void processingInstructionHandler(void *userData, const xmlChar *target, const xmlChar *data)
{
static_cast<XMLTokenizer *>(userData)->processingInstruction(target, data);
}
static void cdataBlockHandler(void *userData, const xmlChar *s, int len)
{
static_cast<XMLTokenizer *>(userData)->cdataBlock(s, len);
}
static void commentHandler(void *userData, const xmlChar *comment)
{
static_cast<XMLTokenizer *>(userData)->comment(comment);
}
static void warningHandler(void *userData, const char *message, ...)
{
va_list args;
va_start(args, message);
static_cast<XMLTokenizer *>(userData)->error(XMLTokenizer::warning, message, args);
va_end(args);
}
static void fatalErrorHandler(void *userData, const char *message, ...)
{
va_list args;
va_start(args, message);
static_cast<XMLTokenizer *>(userData)->error(XMLTokenizer::fatal, message, args);
va_end(args);
}
static void normalErrorHandler(void *userData, const char *message, ...)
{
va_list args;
va_start(args, message);
static_cast<XMLTokenizer *>(userData)->error(XMLTokenizer::nonFatal, message, args);
va_end(args);
}
void XMLTokenizer::finish()
{
xmlSAXHandler sax;
memset(&sax, 0, sizeof(sax));
sax.error = normalErrorHandler;
sax.fatalError = fatalErrorHandler;
sax.characters = charactersHandler;
sax.endElement = endElementHandler;
sax.processingInstruction = processingInstructionHandler;
sax.startElement = startElementHandler;
sax.cdataBlock = cdataBlockHandler;
sax.comment = commentHandler;
sax.warning = warningHandler;
m_parserStopped = false;
m_sawError = false;
m_sawXSLTransform = false;
m_context = createQStringParser(&sax, this, m_doc->document()->URL().ascii());
parseQString(m_context, m_xmlCode);
xmlFreeParserCtxt(m_context);
m_context = NULL;
if (m_sawError) {
insertErrorMessageBlock();
} else {
// Parsing was successful. Now locate all html <script> tags in the document and execute them
// one by one.
addScripts(m_doc->document());
m_scriptsIt = new QPtrListIterator<HTMLScriptElementImpl>(m_scripts);
executeScripts();
}
emit finishedParsing();
}
void XMLTokenizer::insertErrorMessageBlock()
{
// One or more errors occurred during parsing of the code. Display an error block to the user above
// the normal content (the DOM tree is created manually and includes line/col info regarding
// where the errors are located)
// Create elements for display
int exceptioncode = 0;
DocumentImpl *doc = m_doc->document();
NodeImpl* root = doc->documentElement();
if (!root) {
root = doc->createElementNS(XHTML_NAMESPACE, "html", exceptioncode);
NodeImpl* body = doc->createElementNS(XHTML_NAMESPACE, "body", exceptioncode);
root->appendChild(body, exceptioncode);
doc->appendChild(root, exceptioncode);
root = body;
}
ElementImpl* reportElement = doc->createElementNS(XHTML_NAMESPACE, "parsererror", exceptioncode);
reportElement->setAttribute(ATTR_STYLE, "white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black");
ElementImpl* h3 = doc->createElementNS(XHTML_NAMESPACE, "h3", exceptioncode);
h3->appendChild(doc->createTextNode("This page contains the following errors:"), exceptioncode);
reportElement->appendChild(h3, exceptioncode);
ElementImpl* fixed = doc->createElementNS(XHTML_NAMESPACE, "div", exceptioncode);
fixed->setAttribute(ATTR_STYLE, "font-family:monospace;font-size:12px");
NodeImpl* textNode = doc->createTextNode(m_errorMessages);
fixed->appendChild(textNode, exceptioncode);
reportElement->appendChild(fixed, exceptioncode);
h3 = doc->createElementNS(XHTML_NAMESPACE, "h3", exceptioncode);
reportElement->appendChild(h3, exceptioncode);
h3->appendChild(doc->createTextNode("Below is a rendering of the page up to the first error."), exceptioncode);
#ifdef KHTML_XSLT
if (doc->transformSourceDocument()) {
ElementImpl* par = doc->createElementNS(XHTML_NAMESPACE, "p", exceptioncode);
reportElement->appendChild(par, exceptioncode);
par->setAttribute(ATTR_STYLE, "white-space: normal");
par->appendChild(doc->createTextNode("This document was created as the result of an XSL transformation. The line and column numbers given are from the transformed result."), exceptioncode);
}
#endif
root->insertBefore(reportElement, root->firstChild(), exceptioncode);
doc->updateRendering();
}
void XMLTokenizer::addScripts(NodeImpl *n)
{
// Recursively go through the entire document tree, looking for html <script> tags. For each of these
// that is found, add it to the m_scripts list from which they will be executed
if (n->id() == ID_SCRIPT) {
m_scripts.append(static_cast<HTMLScriptElementImpl*>(n));
}
NodeImpl *child;
for (child = n->firstChild(); child; child = child->nextSibling())
addScripts(child);
}
void XMLTokenizer::executeScripts()
{
// Iterate through all of the html <script> tags in the document. For those that have a src attribute,
// start loading the script and return (executeScripts() will be called again once the script is loaded
// and continue where it left off). For scripts that don't have a src attribute, execute the code
// inside the tag
while (m_scriptsIt->current()) {
DOMString scriptSrc = m_scriptsIt->current()->getAttribute(ATTR_SRC);
QString charset = m_scriptsIt->current()->getAttribute(ATTR_CHARSET).string();
// don't load external scripts for standalone documents (for now)
if (scriptSrc != "" && m_doc->document()->part()) {
// we have a src attribute
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -