问题
It's my first time using XML and I am currently trying to return an integer (actually want to return a double but haven't got that far yet) from an XML-file using C++. I'm using RAPIDXML and the following implementation:
All files are in the same directory.
XML (firstxml.xml):
<?xml version="1.0"?>
<test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="firstxsd.xsd">
<A>10</A>
<B>Hello</B>
</test>
XML-Schema (firstxsd.xsd):
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="test">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:integer" name="A"/>
<xs:element type="xs:string" name="B"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
C++ (test.cxx):
#include <iostream>
#include <sstream>
#include <fstream>
#include "rapidxml-1.13/rapidxml.hpp"
#include "rapidxml-1.13/rapidxml_print.hpp"
#include <string>
#include <stdio.h>
#include <vector>
int main(int argc, char* argv[])
{
std::ifstream file ("firstxml.xml");
if (file.is_open())
{
file.seekg(0,std::ios::end);
int size = file.tellg();
file.seekg(0,std::ios::beg);
char* buffer = new char [size];
file.read (buffer, size);
file.close();
rapidxml::xml_document<> doc;
doc.parse<0>(buffer);
rapidxml::xml_node<> *node = doc.first_node()->first_node();
//Line which results in error
std::cout << node->value()*10 << std::endl;
delete[] buffer;
}
}
The error:
test.cxx:52:31: error: invalid operands of types ‘char*’ and ‘int’ to binary ‘operator*’
From the tutorials I have read online, I believe I am constructing the files correctly and so the value parsed into the C++ file from the node A should be an integer. One thing I did notice is that in the RAPIDXML manual the specification of value() is as follows:
Ch* value() const;
Description: Gets value of node. Interpretation of value depends on type of node. Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. Use value_size() function to determine length of the value.
Returns: Value of node, or empty string if node has no value.
So the function definition says it always returns a character pointer, but the line "Interpretation of value depends on type of node" implies it returns a type-dependant value.
Thank you for taking the time to look at my issue, any help is greatly appreciated,
Paul.
回答1:
It is hard to say what does the phrase "Interpretation of value depends on type of node" mean. If the function returns Ch pointer
it will always return such pointer or cause a runtime exception, if library developers provided such feature. Naturally, when you try to multiply a Ch*
by an int you get compile time error.
The only way a function can return a type which depends on call context is to use some special user-defined return type (VARIANT
or something like it). It seems to me that Ch
is just a pseudonim for the basic character type of the library (char
or maybe wchar_t
).
So by that "interpretation..." notice developers probably meant that the user must make a proper interpretation of the character string in accordance to the type of node (which in turn depends on the user-defined schema).
To convert a C-string representation of a number to corresponding types you may use functions from the standard C library, such as atoi()
(converts to int), atof()
(to double) and so on.
回答2:
I guess you want to access "attribute" value, so do something like ...
cout << "Name of my first node is: " << doc.first_node()->name() << "\n";
xml_node<> *node = doc.first_node("foobar");
cout << "Node foobar has value " << node->value() << "\n";
for (xml_attribute<> *attr = node->first_attribute(); attr; attr = attr->next_attribute())
{ cout << "Node foobar has attribute " << attr->name() << " ";
cout << "with value " << attr->value() << "\n";
}
And also have a look at rapidXML tutorial...
http://rapidxml.sourceforge.net/manual.html its easy!
回答3:
Someone correct me if I'm wrong, I believe RapidXML will only give you values as some form of string due to its in-place parsing nature. The class templating might be for handling char vs wide char or something like that, I don't know, I only use char.
What I did to handle extracting values was to add a helper class to rapidxml_utils.hpp (could really have put it anywhere but it made sense there) with some static functions to parse a xml node or attribute to a value (or a default value if it doesn't parse).
These helpers have allowed me to do stuff like:
int Height = xml_helper::GetNodeInt(cur_node->first_node("Height"), 48);
int Width = xml_helper::GetNodeInt(cur_node->first_attribute("Width"), 128);
In your case you might use my helper class like this:
//Line which results in error (altered to use my helper class, if node absent or not parse as integer uses zero)
std::cout << xml_helper::GetNodeInt(node, 0)*10 << std::endl;
My helper class looks like this (I used sscanf to get some level of validation):
class xml_helper
{
public:
// a couple little helpers, lets you do this:
// int Height = xml_helper::GetNodeInt(cur_node->first_node("Height"), 48);
// int Width = xml_helper::GetNodeInt(cur_node->first_node("Width"), 128);
static int GetNodeInt(rapidxml::xml_base<>* node, int DefaultValue)
{
int temp;
try
{
if (node == 0) return DefaultValue;
if (sscanf(node->value(), "%d", &temp) != 1) return DefaultValue;
return temp;
//return atoi(node->value());
}
catch (...) { return DefaultValue; }
}
static unsigned int GetNodeUInt(rapidxml::xml_base<>* node, unsigned int DefaultValue)
{
unsigned int temp;
try
{
if (node == 0) return DefaultValue;
if (sscanf(node->value(), "%u", &temp) != 1) return DefaultValue;
return temp;
//return strtoul(node->value(), NULL, 0);
}
catch (...) { return DefaultValue; }
}
static long long GetNodeLL(rapidxml::xml_base<>* node, long long DefaultValue)
{
long long temp;
try
{
if (node == 0) return DefaultValue;
if (sscanf(node->value(), "%lld", &temp) != 1) return DefaultValue; //C99 covers %lld
return temp;
//return strtoll(node->value(), NULL, 0); //C++11, could use _strtoi64 in VS until then?
}
catch (...) { return DefaultValue; }
}
static double GetNodeDouble(rapidxml::xml_base<>* node, double DefaultValue)
{
double temp;
try
{
if (node == 0) return DefaultValue;
if (sscanf(node->value(), "%lf", &temp) != 1) return DefaultValue; // could use strtod
return temp;
}
catch (...) { return DefaultValue; }
}
static std::string GetNodeStr(rapidxml::xml_base<>* node, std::string DefaultValue)
{
try
{
if (node == 0) return DefaultValue;
return node->value();
}
catch (...) { return DefaultValue; }
}
};
Hopefully this may be helpful to you or someone else using rapidxml and needing a quick way to get integers, doubles, or whatever out of nodes. It can certainly be expanded to other types, I only have types I've needed so far in there now, but you get the gist of it.
来源:https://stackoverflow.com/questions/15081662/errors-with-returning-datatypes-other-than-char-from-xml-file-using-c