C++ 使用libxml2sax解析器获取值错误
我试图用libxml2的sax接口解析一个xml文件。有时它工作得很好,但是我改变了xml中的两行顺序,它仍然有效,并且在解析后一些值变得无效。我将startElementNsSAX2Func用于startElement,它有一个参数const xmlChar**attributes,用于存储当前元素的属性 在startElement方法的开始,我创建了一个简单的对象来处理属性 下面是该类的代码:C++ 使用libxml2sax解析器获取值错误,c++,sax,libxml2,C++,Sax,Libxml2,我试图用libxml2的sax接口解析一个xml文件。有时它工作得很好,但是我改变了xml中的两行顺序,它仍然有效,并且在解析后一些值变得无效。我将startElementNsSAX2Func用于startElement,它有一个参数const xmlChar**attributes,用于存储当前元素的属性 在startElement方法的开始,我创建了一个简单的对象来处理属性 下面是该类的代码: class XMLElementAttributes { public: static con
class XMLElementAttributes {
public:
static const int AttributeArrayWidth = 5;
static const int LocalNameIndex = 0;
static const int PrefixIndex = 1;
static const int URIIndex = 2;
static const int ValueIndex = 3;
static const int EndIndex = 4;
XMLElementAttributes( int nb_attributes, const xmlChar **attributes) :
nb_attributes(nb_attributes),
attributes(attributes){
}
xmlChar* getLocalName( int index ) const {
return (xmlChar*)attributes[ AttributeArrayWidth * index + LocalNameIndex];
}
xmlChar* getValue( int index ) const{
return (xmlChar*)std::string(attributes[ AttributeArrayWidth * index + ValueIndex],attributes[ AttributeArrayWidth * index + EndIndex]).c_str();
}
int getLength() const{
return nb_attributes;
}
private:
int nb_attributes;
const xmlChar ** attributes;
};
xmlChar是Typedef unsigned char xmlChar
然后,如果我需要存储属性的值,我用这个staic方法克隆它。我还尝试使用libxml2的xmlStrdup,结果是一样的:
xmlChar* cloneXMLString(const xmlChar* const source) {
xmlChar* result;
int len=0;
std::cout<<"source"<<std::endl;
while (source[len] != '\0'){
std::cout<<(void*)&source[len] << ": " << source[len] <<std::endl;
len++;
}
std::cout<<std::endl;
std::cout<<"result, "<<std::endl;
result = new xmlChar[len+1];
for (int i=0; i<len; i++){
result[i] = source[i];
std::cout<<(void *)&source[i] << ": "<< source[i] << std::endl;
}
std::cout<<std::endl;
result[len] = '\0';
return result;
}
我这样称呼它:
xmlChar* value = cloneXMLString(attributes.getValue(index));
因此,虽然源的地址没有改变,但它的值却改变了。xml文件的解析继续进行,没有任何问题,克隆后的下一个值再次有效
如果xml文件没有更改,则错误始终位于同一元素和参数。如果我在xml中稍作更改,例如:
<somenodes a="arg1" b="arg2">
<node c="abc" d="def" />
<node c="ghi" d="jkl" />
</somenodes>
StrN从char*创建xmlChar。someVar是MyParser类startElement中的staic字段,也是静态的。在SomeObject的构造函数中,我尝试获得如下属性值:
class SomeObject {
public:
SomeObject( XMLElementAttributes &attributes){
for (int i=0; i< attributes.getLength(); i++) {
xmlChar* name = attributes.getLocalName(i);
if ( xmlStrcmp( name, StrN("somename").xmlCharForm()) == 0 ) {
somename = cloneXMLString(attributes.getValue(i));
}
...
}
}
};
很明显,源代码没有指向有效内存。这可能是因为内存已被释放,也可能是因为它指向已退出的函数中声明的堆栈内存 这样的记忆可能会以一种不可预测的方式被覆盖,这就是你在这里看到的 需要查看更多上下文,特别是如何调用cloneXMLString以及传递给此函数的内存的来源,以获得更详细的答案
<somenodes a="arg1" b="arg2">
<node c="ghi" d="jkl" />
<node c="abc" d="def" />
</somenodes>
void MyParser::startElement( void * ctx,
const xmlChar * localName,
const xmlChar * prefix,
const xmlChar * URI,
int nb_namespaces,
const xmlChar ** namespaces,
int nb_attributes,
int nb_defaulted,
const xmlChar ** attrs ){
XMLElementAttributes attributes ( nb_attributes, attrs );
switch ( state ) {
case Somestate:
if ( xmlStrcmp( localName, StrN("SomeName").xmlCharForm() ) == 0) {
someVar = new SomeObject(attributes);
}
break;
...
}
}
class SomeObject {
public:
SomeObject( XMLElementAttributes &attributes){
for (int i=0; i< attributes.getLength(); i++) {
xmlChar* name = attributes.getLocalName(i);
if ( xmlStrcmp( name, StrN("somename").xmlCharForm()) == 0 ) {
somename = cloneXMLString(attributes.getValue(i));
}
...
}
}
};