-1

重複の可能性:
CのXMLパーサー

こんにちは。Cを使用してXMLファイルから情報を解析/抽出する方法についての簡単なヘルプが必要です。

私が取り組んでいるプロジェクトは、個人的な学習のためだけのものです。私は自分でCを学ぼうとしています。事前に生成されたXML構成ファイルからspaceficテキストまたは作成者の名前を検索するプログラムを作成しようとしています。

以下は私のXMLがどのように見えるかのコピーです:

 <?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>

誰かが私が始めるのを手伝ってくれるか、オンラインまたはチュートリアルの読み物に私を導くことができれば、私は大いに感謝します。

ありがとう、

4

2 に答える 2

0

C ++にも興味がある場合は、rapidxmlを試してみてください。

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

ここでは、3つのレベルの深さの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 に答える
0

いずれにせよ、これはテキストを解析する技術に帰着します。形式文法を読み、FlexとBisonを使用して単純なパーサーを構築する方法を調べる必要があります。

それ以外の場合、パーサーを構築する古典的な方法は、1つの先読みトークンを使用して再帰下降パーサーと呼ばれるものを実行することです。

ただし、パーサーは常にトークナイザーと連携して機能します。トークナイザーのタスクは、特定の文字列をトークンに変換することです(通常は数値として実装されます)。トークは、パーサーが適切なアクションを実行できるように、生成された文字列(または文字列から生成された値(トークン値ではない)、たとえば数値定数)を保持することがよくあります。正規表現は通常、どの文字列をどのトークンに変換するかをトークナイザーに指示するために使用されます。

では、再帰下降パーサーに戻りましょう。本質的には、次のコードのようになります。ただし、詳細については、たとえば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;
}

「 Dosomethingpart」は、値と演算子をスタックにプッシュして、何らかの形の操車場アルゴリズムを実装することができます。または、ASTを作成します。

boost::spiritただし、Boostには、パーサーの構築に使用できる優れたライブラリもあります。

その一方で、XMLパーサーが必要な場合は、すぐに選択できるものがいくつかあります。魔女のXMLパーサーが要件に応じて適切であることを説明するSOのいくつかの素晴らしいフローチャートを見てきました。

于 2013-03-11T21:27:59.223 に答える