Я впервые использую XML, и в настоящее время я пытаюсь вернуть целое число (на самом деле хочу вернуть двойное, но пока не очень далеко) из XML-файла с использованием C ++. Я использую RAPIDXML и следующую реализацию:
Все файлы находятся в одном каталоге.
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-схема (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;
}
}
Ошибка:
test.cxx:52:31: error: invalid operands of types ‘char*’ and ‘int’ to binary ‘operator*’
Из учебников, которые я прочитал в Интернете, я считаю, что я правильно строю файлы, и поэтому значение, анализируемое в файле C ++ из узла A, должно быть целым числом. Одна вещь, которую я заметил, заключается в том, что в руководстве по RAPIDXML спецификация value () выглядит следующим образом:
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.
Таким образом, определение функции говорит, что оно всегда возвращает символьный указатель, но строка «Интерпретация значения зависит от типа узла» подразумевает, что оно возвращает зависящее от типа значение.
Спасибо, что нашли время посмотреть на мою проблему, любая помощь очень ценится,
Павел.
Трудно сказать, что означает фраза «Интерпретация значения зависит от типа узла». Если функция возвращает Ch pointer
он всегда будет возвращать такой указатель или вызывать исключение времени выполнения, если разработчики библиотеки предоставили такую возможность. Естественно, когда вы пытаетесь умножить Ch*
по int вы получаете ошибку времени компиляции.
Единственный способ, которым функция может возвращать тип, который зависит от контекста вызова, — это использовать некоторый специальный определяемый пользователем тип возврата (VARIANT
или как то так). Мне кажется, что Ch
это просто псевдоним для основного типа символов библиотеки (char
или, может быть wchar_t
).
Таким образом, под этим уведомлением «интерпретация …» разработчики, вероятно, подразумевали, что пользователь должен правильно интерпретировать строку символов в соответствии с типом узла (который, в свою очередь, зависит от определенной пользователем схемы).
Чтобы преобразовать представление числа в C-строку в соответствующие типы, вы можете использовать функции из стандартной библиотеки C, такие как atoi()
(конвертируется в int), atof()
(удвоить) и так далее.
Я думаю, вы хотите получить доступ к значению «атрибута», поэтому сделайте что-то вроде …
соиЬ << «Имя моего первого узла:» << doc.first_node () -> имя () << «\ П»;
xml_node<> * node = doc.first_node («foobar»);
соиЬ << «Узел foobar имеет значение» << node-> значение () << «\ П»;
для (xml_attribute<> * attr = node-> first_attribute ();
атр; attr = attr-> next_attribute ())
{
соиЬ << «Узел foobar имеет атрибут» << attr-> имя () << «»;
cout << "with value " << attr->value() << "\n";
}
А также взгляните на руководство по quickXML …
http://rapidxml.sourceforge.net/manual.html это просто!
Кто-то исправит меня, если я ошибаюсь, я полагаю, что RapidXML будет выдавать вам значения только в виде какой-либо строки в силу своего синтаксического анализа на месте. Шаблонные классы могут быть предназначены для обработки char против широких char или что-то в этом роде, я не знаю, я использую только char.
Для обработки извлечения значений я добавил вспомогательный класс в rapidxml_utils.hpp (он мог бы поместить его куда угодно, но это имело смысл) с некоторыми статическими функциями для анализа узла или атрибута xml в значении (или в случае значения по умолчанию, если это не разбирает).
Эти помощники позволили мне делать такие вещи, как:
int Height = xml_helper::GetNodeInt(cur_node->first_node("Height"), 48);
int Width = xml_helper::GetNodeInt(cur_node->first_attribute("Width"), 128);
В вашем случае вы можете использовать мой вспомогательный класс следующим образом:
//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;
Мой вспомогательный класс выглядит следующим образом (я использовал sscanf для получения некоторого уровня проверки):
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; }
}
};
Надеюсь, это может быть полезно вам или кому-то еще, использующему rapidxml и нуждающемуся в быстром способе получить целые, двойные или что-либо еще из узлов. Конечно, его можно распространить и на другие типы, у меня есть только те типы, которые мне были нужны, но вы понимаете суть.