Tool:IllyriadParser
From Arcanum Illyria
| IllyriadParser | |
| About | |
|---|---|
| Author | HonoredMule (User, Talk) |
| Type | XML Parser |
| Version | 1.0 (2011-01-31) |
| Description | Simplifies parsing datafiles |
| Dependencies | PHP |
| PHP Scripts - Tools | |
IllyriadParser is an easy-to-use class-based system specially for Illyriad's data files. Rather than being a finished but also inflexible solution, it's up to you to write the classes that read specific information and post it to whatever data store you like using whatever structure you like. In this manner, it supports all past, present, and likely future formats at any file size while remaining extremely simple to use. The classes can be as complete or as brief as desired.
Contents |
How to Use It
Each class you write (like AllianceParser extends RowParser) handles a single table, and each instance of the class handles one row. Each protected method you write (like parse_allianceticker($data, $attrs)) receives the data specific to that node which you can compile as desired into $this->data using whatever structure and format you like. When the information within the handled row is complete, the method processData() will be called--this is the only one you must implement. From there, you can add information from parent classes and push $this->data wherever you like. Because YOU defined the data layout, query builders can easily and automatically submit the data to database tables YOU defined, and other software you write can work with it easily as well, having just what it needs and where it wants it. For added convenience, when you run your PHP through a web server, the classes will spit out lists of the nodes that were found and not parsed, serving as a guide while you're still writing your classes.
The parser classes can be nested as well--for example, RoleParser will parse the roles in an alliance, and has access to the information from its parent AllianceParser. The classes can stack to any depth and still find a particular parent by node name, so all the structural/relational information you need will be preserved. The system is also clever enough to know an alliance node within an alliance node isn't really an alliance within an alliance--the outer one is an alliance object and the inner one is some of the important information. So, when quirks like that are encountered, only one AllianceParser is created, with the inner data-rich node getting handled by parse_alliance($data, $attrs) and the encapsulating one by parse_outer_alliance($data, $attrs).
The example below demonstrates most of the system's capabilities.
Example
Usage
- <?php
- include('IllyriadParser.php');
- // just a little helper function
- function debug($data) {
- echo "<pre>";
- echo "</pre>";
- }
- class AllianceParser extends RowParser {
- protected function processData() {
- // just showing the data gathered
- echo "DATA: ";
- debug($this->data);
- }
- protected function parse_allianceticker($data, $attrs) {
- }
- protected function parse_alliance($data, $attrs) {
- $this->data['id'] = (int)$attrs['id'];
- }
- protected function parse_foundedbyplayerid($data, $attrs) {
- $this->data['founder'] = (int)$attrs['id'];
- }
- protected function parse_alliancecapitaltownid($data, $attrs) {
- $this->data['capital'] = (int)$attrs['id'];
- }
- protected function parse_foundeddatetime($data, $attrs) {
- }
- }
- class RoleParser extends RowParser {
- protected function processData() {
- // fetch information encapsulated in a parent parser
- $alliance = $this->illyParser->parentRow('alliance');
- $this->data['alliance'] = $alliance['id'];
- // just showing the data gathered
- echo "ROLE: ";
- debug($this->data);
- }
- protected function parse_role($data, $attrs) {
- $this->data['id'] = (int)$attrs['id'];
- }
- }
- $handler = new IllyriadParser();
- $handler->parseFile('alliances-2010-08-07.xml');
- ?>
Output
ROLE:Array
(
[id] => 1
[name] => Founder
[alliance] => 1
)
Unhandled Nodes: heirarchy, outer_role
...SNIP...
ROLE:Array
(
[id] => 2
[name] => New Member
[alliance] => 1
)
Unhandled Nodes: heirarchy, outer_role
DATA:Array
(
[id] => 1
[name] => Harmless?
[founder] => 10
[capital] => 27
[ticker] => H?
[founded] => 1267121887
)
Unhandled Nodes: alliancecapitallastmoved, alliancetaxrate, alliancetaxratelastchanged, membercount, totalpopulation, roles, proposedbyalliance, acceptedbyalliance, relationshiptype, relationshipttype, establishedsince, relationship, relationships, outer_alliance
ROLE:Array
(
[id] => 27
[name] => Leader
[alliance] => 2
)
Unhandled Nodes: heirarchy, outer_role
...SNIP...
The Script
- <?php
- // IllyriadParser.php by HonoredMule
- // license: LGPL
- abstract class RowParser {
- protected $illyParser = null;
- private $depth = 0;
- function __construct($parser) {
- $this->illyParser = $parser;
- }
- function openElement($element, $attrs) {
- $this->stackAttrs[++$this->depth] = $attrs;
- $depth = (int)@$this->nested_tags[$element];
- }
- function dataElement($data) {
- $this->stackData[$this->depth] = $data;
- }
- function closeElement($element) {
- $i = $this->depth;
- $func = 'parse_'.$nest.$element;
- $this->$func($this->stackData[$i], $this->stackAttrs[$i]);
- else
- $this->unhandled_tags[$nest.$element] = true;
- if(--$this->depth == 0)
- $this->processData();
- return $this->depth;
- }
- function getData() {
- return $this->data;
- }
- // Perform any post processing--including fetching data from parent tables using
- // $this->parser->parentRow('nodename')--and commit the data to some data store
- // or (for example) a large SQL query builder
- abstract protected function processData();
- function __destruct() {
- }
- }
- class IllyriadParser {
- public $date;
- public $server;
- private $parser;
- private $data;
- function __construct() {
- }
- function parseFile($filepath) {
- }
- function openElement($parser, $element, $attrs) {
- $node = array_peek($this->nodeStack);
- $node->openElement($element, $attrs);
- }
- function dataElement($parser, $data) {
- $node = array_peek($this->nodeStack);
- $node->dataElement($data);
- }
- function closeElement($parser, $element) {
- $node = array_peek($this->nodeStack);
- return;
- if($node->closeElement($element) === 0)
- }
- function findParent($type) {
- return array_peek($this->nodeStack);
- foreach($this->nodeStack as $obj) {
- return $obj;
- }
- throw new Exception("Cannot find $type parser on the stack");
- }
- function parentRow($type) {
- return $this->findParent($type)->getData();
- }
- }
- function array_peek($array, $n = 0) {
- return false;
- $n++;
- if($l < $n)
- return false;
- return $array[$l - $n];
- }
- ?>
