简体   繁体   中英

How do I write a generic C++ function to parse xml into structs?

I have a collection of xml data files representing objects of interest in images (rectangles, points, labelled faces, etc.) that I want to parse to produce vectors of structs. The files are manually created (and so are not just the result of serialising some C++ objects) and are of the following form:

<root>
<image filename=whatever>
<object>
  <x>1</x>
  <y>2</y>
</object>
<object>
  <x>3</x>
  <y>4</y>
</object>
</image>
<image filename=something>
 ...
</image>
</root>

So a collection of images, each of which contains a collection of object children, each of which has children giving the data relevant to that object. The structure of this data varies between files, eg in one file each object might just have an x and ay and in another each object might contain ints x1, y1, x2, y2 and a double z.

I want to parse such a file to produce a vector of Objects, where Object is a struct, in this case of the form struct Object { int x; int y; }.

For different choices of Object, I've currently got separate functions that use rapidxml to parse the xml in identical ways, except for which fields they extract.

I'd like to write a templated function so that you can merely specify the elements of a struct in some way and have the function return a vector of the appropriate structs. ie The user should specify a list of pairs ("x1", int), ("x2", int), etc. and have the rest of the work be done automatically.

I'm sure there must be a nice boost solution to this problem that avoids having to use XML schema. How do I do this?

You could try Boost Property Tree .

It allows you to write your own load/save functions to map XML (or INI or JSON) data onto your own structures. See the tutorial .

It even uses RapidXML which you're already using.

Edit:

You could try something like

template<typename T>
struct Field
{
    typedef T type;
    std::string name;
};

template<typename... Fields>
std::tuple<typename Fields::type...>
load(const Data& data, Fields... f)
{
    return std::make_tuple( data.get<typename Fields::type>(f.name)... );
}

Where Data is some source of the input data, like a boost::ptree , and you'd use that function like this:

load(d, Field<int>{"x1"}, Field<int>{"x2"} );

Then you'd just need each data type to be constructible from a tuple of the right types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM