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