Schemeer,一个半 XML 和 JSON 处理程序
这是一个可以通过修改配置文件来处理 XML 文档或 JSON 的库。
引言
本文介绍了一个可以处理任何字符串树结构的应用,例如 XML 文档或 JSON 文档。我的应用需要一个模式文件和一个配置文件来定义目标文档结构。
使用代码
我将输入文档抽象成一个由树节点组合而成的树结构。每个节点包含一个模式短语,每个短语由单词组合而成。单词是一个字符串向量。输入文档的每个字符在保存到单词中之前都有一个输入类型。输入类型包括:
//
// The input object struct
//
enum ObjectType{
NORMAL_WORD,
KEY_WORD,
INVALID_WORD,
SEPARATE_LETTER,
SPECIAL_LETTER,
IGNORE_LETTER,
NORMAL_LETTER,
INVALID_LETTER,
SCHEME_PHRASE
};
关键字、无效单词、特殊字符、忽略字符、无效字符等等。这些字符和单词在应用程序初始化阶段输入的配置文件中定义。它们被保存在一个 Dictionary
类中。
//The init function
bool Dictionary::init(std::string configFile){
FILE *file = NULL;
fopen_s(&file,configFile.c_str(),"r");
if (file == NULL) return false;
insertWords(file,KEY_WORD);
insertLetters(file,SPECIAL_LETTER);
insertLetters(file,SEPARATE_LETTER);
insertLetters(file,IGNORE_LETTER);
insertLetters(file,INVALID_LETTER);
fclose(file);
return true;
}
配置文件的每一行都是一种输入对象类型,它们之间用 ',' 分隔。在过滤输入字符并将它们构建成单词之后,使用文件分析类来分析输入字符串并将它们组织成树模型。文件分析类使用 Scheme
类来匹配输入文档。匹配方程在模式文件中定义。
//Init Scheme class
void Scheme::init(std::string config){
if (dictionary == NULL) return;
FILE *file = NULL;
fopen_s(&file,config.c_str(),"r");
while(file != NULL && !feof(file)){
std::string sentence;
readSentence(file,sentence);
if (sentence.empty() == true) continue;
SchemePhrase equation;
unsigned int offset = 0;
analyzeSentence(sentence,offset,&equation);
equations.push_back(equation);
}
if (file != NULL) fclose(file);
}
//Analyze the input object into tree elements</span>
void FileAnalysis::analyze(){
std::vector<InputObject*> elements;
while(true){
InputObject* object = fileReaders->getNextObject();
if (object == NULL) break;
elements.push_back(object);
}
std::vector<Memo> &process = scheme->match(elements);
TreeNode *curNode = tree->getRoot();
for(unsigned int p = 0; p < process.size(); ++p){
Memo &m = process[p];
if (m.operation->getType() == SCHEME_PHRASE){
SchemePhrase * phrase = dynamic_cast<SchemePhrase*>(m.operation);
if (phrase->getOperation() == UPCHILD){
curNode = curNode->getFather();
}else if (phrase->getOperation() == DOWNCHILD){
curNode = curNode->getLastChild();
}
}else if (m.operation->getType() == NORMAL_WORD){
curNode->makeChild(dynamic_cast<Word*>(m.operation)->getContent(),
dynamic_cast<Word*>(m.object)->getContent());
}
}
}
树节点使用组件设计模式。它们中的每一个都有一个值和一个名称参数,并且具有指向其子节点的指针,这些子节点是相同类型。
class BaseNode
{
public:
BaseNode(void);
~BaseNode(void);
void setName(std::string n){ name = n; }
void setValue(std::string v){ value = v;}
std::string getName(){return name;}
std::string getValue(){return value;}
private:
std::string name;
std::string value;
};
class TreeNode :
public BaseNode
{
public:
TreeNode(TreeNode *father = NULL,std::string name="", std::string value = "");
virtual ~TreeNode(void);
TreeNode* getNode(std::string name, std::string value = "");
void addNode(TreeNode node){elements.push_back(node);}
TreeNode* makeChild(std::string name, std::string value = "");
TreeNode* getFather();
TreeNode* getLastChild();
TreeNode* getElement(int i){return &elements[i];}
unsigned int size(){return elements.size();}
std::vector<TreeNode*> getNodes(std::string name, std::string value = "");
std::string get(std::string name);
std::vector<std::string> gets(std::string name);
void clear();
private:
TreeNode *father;
std::vector<TreeNode> elements;
};
处理完输入文档后,可以通过名称值获取树的节点。
std::vector<TreeNode*> TreeNode::getNodes(std::string name, std::string value){
std::vector<TreeNode *> result;
for(unsigned int i = 0; i < elements.size(); ++i){
if (elements[i].getName() == name && (value == "" || elements[i].getValue() == value)){
result.push_back(&(elements[i]));
}
}
return result;
}
示例
初始化模式文件和配置文件
ModelTree tree;
Dictionary dic;
Scheme sch(&dic);
FileAnalysis analysis;
TreeNode * root;
analysis.setDictionary(&dic);
analysis.setScheme(&sch);
analysis.setTree(&tree);
dic.init("config\\config.txt");
sch.init("config\\scheme.txt");
analysis.setFile("input.txt");
analysis.analyze();
处理输入文档并打印它们:
root = tree.getRoot();
printNode(root,0);
然后处理 JSON 文档。输入配置
meta;
44;125;93;123;91;34;58;
32;9;10;
0;1;2;3;4;5;6;7;8;11;12;13;14;15;16;17;18;19;20;21;22;23;24;25;26;27;28;29;30;31;127;
;
输入模式:
;{"element":\d ["value"|\[ self [, self]* \]]1 \u [,"element":\d ["value"|\[ self [, self]* \]]1 \u]* }
输入文件
{ "programmers": [
{ "firstName": "Brett", "lastName":"McLaughlin", "email": "be@gmail.com" },
{ "firstName": "Jason", "lastName":"Hunter", "email": "abc@gmail.com" },
{ "firstName": "Elliotte", "lastName":"Harold", "email": "ell@163.com" }
],
"authors": [
{ "firstName": "Isaac", "lastName": "Asimov", "genre": "sciencefiction" },
{ "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },
{ "firstName": "Frank", "lastName": "Peretti", "genre": "christianfiction" }
],
"musicians": [
{ "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },
{ "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }
] }
输出
然后处理 XMLdocument
。
输入配置
meta;
60;61;62;63;92;34;47;
32;9;10;
0;1;2;3;4;5;6;7;8;11;12;13;14;15;16;17;18;19;20;21;22;23;24;25;26;27;28;29;30;31;127;
;
输入模式:
;<element\d [attribute[="\dvalue\u"]1]* >[value|self]*\u</element>
;<element\d [attribute[="\dvalue\u"]1]* \u/>
输入文件
<book title="facebook" >
<auther><lxdfigo name="lxd" >
<age value="16" />
</lxdfigo></auther>
<price value="216.0" />
<date value="2012-2-3" />
</book>
<book2 title="facebook" >
<auther><lxdfigo name="lxd" >
<age value="16" />
</lxdfigo></auther>
<price value="216.0" />
<date value="2012-2-3" />
</book2>
<book title="facebook" >
<auther><lxdfigo name="lxd" >
<age value="16" />
</lxdfigo></auther>
<price value="216.0" />
<date value="2012-2-3" />
</book>
<book2 title="facebook" >
<auther><lxdfigo name="lxd" >
<age value="16" />
</lxdfigo></auther>
<price value="216.0" />
<date value="2012-2-3" />
</book2>
输出