-1

Possible Duplicate:
XML Parser for C

Hello there I need some quick help on how to parse/extract information out of an XML file using C.

The project I am trying to work on is just for personal learning. I'm trying to learn C on my own. I am trying to write a program that will search about spacefic text or the name of the author from a pregenerated XML config file.

Below is a copy of what my XML looks like:

 <?xml version="1.0" encoding="ISO-8859-1"?>
<config>
    <quote>
    <text>
        "Moral indignation is jealous with a halo."
    </text>
    <author>
        H.G. Wells
    </author>
    <livedfrom>
        1866-1946
    </livedfrom>
    <extrainfo />
</quote>

If someone can just help me get started or direct me to some reading material online or tutorial, I would greatly appreciate.

Thanks,

4

2 回答 2

0

无论如何,这将归结为解析文本的艺术。你应该阅读形式语法,也许看看如何使用 Flex 和 Bison 构建一个简单的解析器。

否则,构建解析器的经典方法是使用一个前瞻令牌来执行所谓的递归体面解析器。

然而,解析器总是与分词器协同工作。标记器的任务是将某些字符串转换为标记(通常实现为数值)。令牌通常携带生成它的字符串(或从字符串生成的某个值(不是令牌值),例如某个数字常量),因此解析器可以采取适当的行动。正则表达式通常用于告诉分词器将什么字符串转换为什么令牌。

所以再次回到递归体面的解析器。它本质上看起来像下面的代码。但请查看例如Wikipedia以获取更多信息。

void handle_token_foo()
{
  //Do something now when we know we handle token FOO
  ....
  //Find next token and take appropriate action
  Token t = tokenizer.get_next_token();
  if(t == TOKEN_TYPE_BAR)
  {
    parse_token_bar();  
  }
  else if(t == TOKEN_TYPE_FOO)
  {
    parse_token_foo();
  }
  else if(t == TOKEN_TYPE_END)
  {
     return;
  }
  throw ParseError();
  return 
}

void handle_token_bar()
{
  //Do something now when we know we handle token BAR
  ....
  //Find next token and take appropriate action

  Token t = tokenizer.get_next_token();
  if(t == TOKEN_TYPE_BAR)
  {
    parse_token_bar();  
  }
  else if(t == TOKEN_TYPE_FOO)
  {
    parse_token_foo();
  }
  else if(t == TOKEN_TYPE_END)
  {
     return;
  }
  throw ParseError();
  return;
}

“做某事”可以将值和运算符压入堆栈以实现某种形式的分流场算法。或者构建一个AST

然而,在 Boostboost::spirit中也有一个很好的库可以用来构建解析器。

所以另一方面,如果您只想要一个 XML 解析器,则有许多现成的可供选择。在 SO 上看到了一些很好的流程图,描述了 witch XML 解析器是否很好,具体取决于您的要求。

于 2013-03-11T21:27:59.223 回答
0

如果你也对 C++ 感兴趣,你可以试试 rapidxml:

http://rapidxml.sourceforge.net/
http://rapidxml.sourceforge.net/manual.html

在这里,我编写了一个示例代码,它解析和打印深度为三个级别的 xml 的内容(与您的一样):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "./rapidxml-1.13/rapidxml.hpp"
#include "./rapidxml-1.13/rapidxml_print.hpp"
#include <iostream>
#include <fstream>

using namespace std;
using namespace rapidxml;


void process_xml(const char* xml){
    xml_document<> doc;
    char text[strlen(xml)+1];
    strcpy(&text[0], xml);
    try{
        doc.parse<parse_default>(text);
    }
    catch(rapidxml::parse_error &ex){
        cout << "error: rapidxml::parse_error\n";
        return;
    }

    xml_node<> *ptr=NULL;
    try{
        if (doc.first_node()!=NULL){
            for (xml_node<> *node=doc.first_node(); node; node=node->next_sibling()){
                cout << "node->name: " << node->name() << endl;
                if (strcmp(node->name(), "")!=0){
                    xml_node<> *content_node = node->first_node();
                    ptr=content_node;
                    while ((content_node!=NULL) && (strcmp(content_node->name(), "")!=0)){
                        cout << "\t>>" << content_node->name() << endl;

                        for (xml_node<> *node_3rd=content_node->first_node(); node_3rd; node_3rd=node_3rd->next_sibling()){
                            cout << "name: " << node_3rd->name() << "; ";
                            cout << "value: " << node_3rd->value() << endl;
                        }

                        content_node=content_node->next_sibling();
                    }
                }
            }
            cout << "\n";
        }
    }
    catch(...){
        cout << "error: in reading an event!";
    }
}


int main(void){
    //read the xml from an input file
    std::ifstream ifs("in_file.txt");
    std::string xml;
    xml.assign(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());

    //process the xml
    process_xml(xml.c_str());

    return 0;
}
  • 注意:要将您的 xml 转换为有效的 xml,您必须关闭所有标签,因此您应该</config>在末尾添加,因为您<config>在开头有。

要运行此代码,您必须从我提供的链接下载 rapidxml 并将其解压缩到您的项目文件夹中。编译不需要额外的标志。

然后,使用带有更正 xml 的输入文件“in_file.txt”(*参见上面的通知),此代码将作为输出生成:

node->name: config
    >>quote
name: text; value: 
            "Moral indignation is jealous with a halo."

name: author; value: 
            H.G. Wells

name: livedfrom; value: 
            1866-1946

name: extrainfo; value: 

然后,您可以将结果值存储在变量、结构或任何您想要的东西中。

于 2013-03-11T21:48:45.027 回答