/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is TransforMiiX XSLT processor. * * The Initial Developer of the Original Code is The MITRE Corporation. * Portions created by MITRE are Copyright (C) 1999 The MITRE Corporation. * * Portions created by Keith Visco as a Non MITRE employee, * (C) 1999 Keith Visco. All Rights Reserved. * * Contributor(s): * Tom Kneeland, tomk@mitre.org * -- original author. * * Keith Visco, kvisco@ziplink.net * -- finished implementation. Too many changes to list here. * * Bob Miller, Oblix Inc., kbob@oblix.com * -- fixed assignment to "true" to be MB_TRUE, in ::parse() * * Marina Mechtcheriakova, mmarina@mindspring.com * -- UNICODE fix in method startElement, changed casting of * char* to PRUnichar* to use the proper String constructor, * see method startElement * -- Removed a number of castings of XML_Char to PRUnichar since they * were not working on Windows properly * */ #include "XMLParser.h" #include "txURIUtils.h" #ifndef TX_EXE #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsISyncLoadDOMService.h" #include "nsNetUtil.h" #else #include "xmlparse.h" #endif /** * Implementation of an In-Memory DOM based XML parser. The actual XML * parsing is provided by EXPAT. **/ /** * Creates a new XMLParser **/ XMLParser::XMLParser() { } //-- XMLParser XMLParser::~XMLParser() { //-- clean up } //-- ~XMLParser Document* XMLParser::getDocumentFromURI(const nsAString& href, Document* aLoader, nsAString& errMsg) { #ifndef TX_EXE nsCOMPtr documentURI; nsresult rv = NS_NewURI(getter_AddRefs(documentURI), href); NS_ENSURE_SUCCESS(rv, 0); nsCOMPtr theDocument; nsCOMPtr loaderDocument = do_QueryInterface(aLoader->getNSObj()); nsCOMPtr loadGroup; nsCOMPtr loaderUri; loaderDocument->GetDocumentLoadGroup(getter_AddRefs(loadGroup)); loaderDocument->GetDocumentURL(getter_AddRefs(loaderUri)); NS_ENSURE_TRUE(loaderUri, 0); nsCOMPtr channel; rv = NS_NewChannel(getter_AddRefs(channel), documentURI, nsnull, loadGroup); NS_ENSURE_SUCCESS(rv, 0); nsCOMPtr loader = do_GetService("@mozilla.org/content/syncload-dom-service;1", &rv); NS_ENSURE_SUCCESS(rv, 0); rv = loader->LoadDocument(channel, loaderUri, getter_AddRefs(theDocument)); if (NS_FAILED(rv) || !theDocument) { errMsg.Append(NS_LITERAL_STRING("Document load of ")); errMsg.Append(href); errMsg.Append(NS_LITERAL_STRING(" failed.")); return nsnull; } return new Document(theDocument); #else istream* xslInput = URIUtils::getInputStream(href, errMsg); Document* resultDoc = 0; if ( xslInput ) { resultDoc = parse(*xslInput, href); delete xslInput; } if (!resultDoc) { errMsg.Append(getErrorString()); } return resultDoc; #endif } #ifdef TX_EXE /*------------------------------------- * Sax related methods for XML parsers * ------------------------------------*/ extern "C" { void charData(void* userData, const XML_Char* s, int len); int startElement(void *userData, const XML_Char* name, const XML_Char** atts); int endElement(void *userData, const XML_Char* name); int piHandler(void *userData, const XML_Char *target, const XML_Char *data); void commentHandler(void *userData, const XML_Char *s); } /** * Parses the given input stream and returns a DOM Document. * A NULL pointer will be returned if errors occurred **/ Document* XMLParser::parse(istream& inputStream, const nsAString& uri) { const int bufferSize = 1000; char buf[bufferSize]; int done; errorString.Truncate(); if ( !inputStream ) { errorString.Append(NS_LITERAL_STRING("unable to parse xml: invalid or unopen stream encountered.")); return nsnull; } XML_Parser parser = XML_ParserCreate(nsnull); ParserState ps; ps.document = new Document(); ps.document->documentBaseURI = uri; ps.currentNode = ps.document; XML_SetUserData(parser, &ps); XML_SetElementHandler(parser, startElement, endElement); XML_SetCharacterDataHandler(parser, charData); XML_SetProcessingInstructionHandler(parser, piHandler); XML_SetCommentHandler(parser,commentHandler); do { inputStream.read(buf, bufferSize); done = inputStream.eof(); if (!XML_Parse(parser, buf, inputStream.gcount(), done)) { errorString.AppendWithConversion(XML_ErrorString(XML_GetErrorCode(parser))); errorString.Append(NS_LITERAL_STRING(" at line ")); errorString.AppendInt(XML_GetCurrentLineNumber(parser)); done = MB_TRUE; delete ps.document; ps.document = nsnull; } } while (!done); inputStream.clear(); //if (currentElement) //theDocument->appendChild(currentElement); // clean up XML_ParserFree(parser); return ps.document; } const nsAString& XMLParser::getErrorString() { return errorString; } int startElement(void *userData, const XML_Char *name, const XML_Char **atts) { ParserState* ps = (ParserState*)userData; Element* newElement; XML_Char** theAtts = (XML_Char**)atts; newElement = ps->document->createElement(nsDependentString((const PRUnichar*)name)); while (*theAtts) { nsDependentString attName((const PRUnichar*)*theAtts++); nsDependentString attValue((const PRUnichar*)*theAtts++); newElement->setAttribute(attName, attValue); } ps->currentNode->appendChild(newElement); ps->currentNode = newElement; return XML_ERROR_NONE; } //-- startElement int endElement(void *userData, const XML_Char* name) { ParserState* ps = (ParserState*)userData; if (ps->currentNode->getParentNode()) ps->currentNode = ps->currentNode->getParentNode(); return XML_ERROR_NONE; } //-- endElement void charData(void* userData, const XML_Char* s, int len) { ParserState* ps = (ParserState*)userData; Node* prevSib = ps->currentNode->getLastChild(); if (prevSib && prevSib->getNodeType() == Node::TEXT_NODE){ ((NodeDefinition*)prevSib)->appendData((const PRUnichar*)s, len); } else { // s is not null-terminated so we use Substring here. Node* node = ps->document->createTextNode(Substring((const PRUnichar*)s, (const PRUnichar*)s + len)); ps->currentNode->appendChild(node); } } //-- charData void commentHandler(void* userData, const XML_Char* s) { ParserState* ps = (ParserState*)userData; Node* node = ps->document->createComment(nsDependentString((const PRUnichar*)s)); ps->currentNode->appendChild(node); } //-- commentHandler /** * Handles ProcessingInstructions **/ int piHandler(void *userData, const XML_Char *target, const XML_Char *data) { ParserState* ps = (ParserState*)userData; ProcessingInstruction* node = ps->document->createProcessingInstruction(nsDependentString((const PRUnichar*)target), nsDependentString((const PRUnichar*)data)); ps->currentNode->appendChild(node); return XML_ERROR_NONE; } //-- piHandler #endif