On the fly XML parser

Romain Behar <romainbehar-/[email protected]> Thu, 3 Jun 2004 03:33:25 -0700 (PDT)
Newsgroups gmane.comp.parsers.hapy.user
Message-ID <[email protected]>
--0-549673409-1086258805=:91533
Content-Type: text/plain; charset=us-ascii
Content-Id: 
Content-Disposition: inline


The attached example is an attempt for an "on the fly"
XML parser. XML files tend to get very big: the idea
is not to load the entire file into memory but to
parse it when loading the file.

The parser was modified to use prefix parsing, and the
rNode and rElement merged into a new rXML rule. We
loose the element nesting information: a stack needs
to be set up to keep track of nesting level or skip
entire blocks.

Could the prefix parser stop on defined rules, that
would avoid changing the grammar?


There is another tweak in the prefix parsing loop:

char c = file.get();
while(c != ' ' && c != '\n' && c != '\r' && c != '\t')
{
 ...
}

helps the parser not to stop on string parsing (e.g.
"<!--" in rComment);

is there a better way to handle this trick?


 Regards,

  Romain



	
		
__________________________________
Do you Yahoo!?
Friends.  Fun.  Try the all-new Yahoo! Messenger.
http://messenger.yahoo.com/ 
--0-549673409-1086258805=:91533
Content-Type: text/x-c++src; name="xml.cc"
Content-Description: xml.cc
Content-Disposition: inline; filename="xml.cc"

/* Hapy is a public domain software. See Hapy README file for the details. */

#include <Hapy/Parser.h>
#include <Hapy/Rules.h>
#include <Hapy/PreeFarm.h>
#include <Hapy/Assert.h>
#include <Hapy/IoStream.h>

#include <algorithm>
#include <fstream>


using namespace Hapy;

Rule rXML("xml", 0);
Rule rNode("node", 0);
Rule rPi("pi", 0);
Rule rElement("element", 0);
Rule rOpenElement("open-element", 0);
Rule rCloseElement("close-element", 0);
Rule rClosedElement("closed-element", 0);
Rule rText("text", 0);
Rule rAttr("attr", 0);
Rule rName("name", 0);
Rule rValue("value", 0);
Rule rComment("comment", 0);

static
Rule grammar() {

	rXML = rOpenElement | rText | rPi | rComment | rCloseElement | rClosedElement;
	rXML.trim(*space_r);
	//rNode = rElement | rText | rPi | rComment;
	//rNode.trim(*space_r);
	//rElement = rOpenElement >> *rNode >> rCloseElement | rClosedElement;

	rPi = "<?" >> rName >> *(anychar_r - "?>") >> "?>";

	rOpenElement = "<" >> rName >> *rAttr >> ">";
	rCloseElement = "</" >> rName >> ">";
	rClosedElement = "<" >> rName >> *rAttr >> "/>";

	rText = +(anychar_r - '<');

	rAttr = rName >> '=' >> rValue;
	rName = alpha_r >> *(alnum_r | '_' | ':');
	rValue = quoted_r(anychar_r);

	rComment = "<!--" >> *(anychar_r - "-->") >> "-->";

	// trimming rules
	rText.verbatim(true);
	rName.verbatim(true);
	rValue.verbatim(true);

	// parse tree shaping rules
	rText.leaf(true);
	rName.leaf(true);
	rValue.leaf(true);

	// parsing optimization rules
	rText.committed(true);
	rName.committed(true);
	rValue.committed(true);
	rNode.committed(true);

	// skip comments
	rComment.verbatim(true);
	rComment.leaf(true);

	return rXML;
}

// calculate expression value
void intrpExpr(const Pree& expr)
{
	const Pree &alt = expr[0];
	if(alt.rid() == rOpenElement.id())
		{
			const Pree& name = alt.find(rName.id());
			std::cout << "open : " << name.image() << std::endl;
		}
	else if(alt.rid() == rText.id())
		{
			std::cout << "text " << alt.image() << std::endl;
		}
	else if(alt.rid() == rPi.id())
		{
			std::cout << "pi : " << alt.image() << std::endl;
		}
	else if(alt.rid() == rComment.id())
		{
			// Skip
		}
	else if(alt.rid() == rCloseElement.id())
		{
			const Pree& name = alt.find(rName.id());
			std::cout << "close : " << name.image() << std::endl;
		}
	else if(alt.rid() == rClosedElement.id())
		{
			std::cout << "closed : " << alt.image() << std::endl;
		}
	else
		std::cout << "Unknown element" << std::endl;
}

bool interpret(const Result& result)
{
	if(result.statusCode == Result::scMatch)
		{
			intrpExpr(result.pree);
			return true;
		}

	if(result.input.size() > 0)
		std::cerr << result.location() << ": syntax error" << std::endl;

	return false;
}

int main()
{

	Parser parser;
	parser.grammar(grammar());

	std::ifstream file("example.xml");
	if(!file.good())
		{
			std::cerr << "Could not open file." << std::endl;
			return 1;
		}

	do
		{
			parser.moveOn();
			if(parser.begin())
				{
					while(parser.step())
						{
							if(parser.sawDataEnd())
								continue;

							if(file.eof())
								{
									parser.sawDataEnd(true);
									continue;
								}

							char c = file.get();
							while(c != ' ' && c != '\n' && c != '\r' && c != '\t')
								{
									parser.pushData(string(1, c));
									c = file.get();
if(file.eof())
{
									parser.sawDataEnd(true);
	break;
}
								}

							parser.pushData(string(1, c));
						}
				}

			parser.end();
		}
	while(interpret(parser.result()));

	return 0;
}



--0-549673409-1086258805=:91533--


-------------------------------------------------------
This SF.Net email is sponsored by the new InstallShield X.
From Windows to Linux, servers to mobile, InstallShield X is the one
installation-authoring solution that does it all. Learn more and
evaluate today! http://www.installshield.com/Dev2Dev/0504