421
社区成员




xml;parse;
开发板型号:
芯片:
内核版本:
OH版本:OpenHarmony 3.1 Release
问题现象:OpenHarmony 3.1 Release系统上使用@ohos.xml中的xmlPullParser.parse接口解析XML文件获取Tag属性值,同个Tag只能获取到第一个属性值,无法获取其之后的属性值。
测试步骤:
import xml from '@ohos.xml';
var strXml =
'<?xml version="1.0" encoding="utf-8"?>' +
'<!DOCTYPE note [\n<!ENTITY foo "baa">]>' +
'<note importance="high" logged="true">' +
' <![CDATA[\r\nfuncrion matchwo(a,6)\r\n{\r\nreturn 1;\r\n}\r\n]]>' +
' <!--Hello, World!-->' +
' <company>John & Hans</company>' +
' <title>Happy</title>' +
' <title>Happy</title>' +
' <lens>Work</lens>' +
' <lens>Play</lens>' +
' <?go there?>' +
' <a><b/></a>' +
' <h:table xmlns:h="http://www.w3.org/TR/html4/">' +
' <h:tr>' +
' <h:td>Apples</h:td>' +
' <h:td>Bananas</h:td>' +
' </h:tr>' +
' </h:table>' +
'</note>';
var arrayBuffer = new ArrayBuffer(strXml.length*2);
var bufView = new Uint8Array(arrayBuffer);
var strLen = strXml.length;
for (var i = 0; i < strLen; ++i) {
bufView[i] = strXml.charCodeAt(i);
}
var that = new xml.XmlPullParser(arrayBuffer, 'UTF-8');
var str = '';
function func2(name, value){
str += name+':'+value;
return true;
}
var options = {supportDoctype:true, ignoreNameSpace:true, attributeValueCallbackFunction:func2}
that.parse(options);
console.log('xml str value:' + str);
通过下面的方式,可以解决此问题,在源代码base/compileruntime/js_api_module/xml/js_xml.cpp的 XmlPullParser::ParseAttri 解析xml属性的方法中,改动for循环中最后一行代码:
bool XmlPullParser::ParseAttri(napi_env env, napi_value thisVar) const
{
for (size_t i = 0; i < attriCount_; ++i) {
napi_value returnVal = nullptr;
size_t argc = 3; // 3: number of args
napi_value global = nullptr;
napi_get_global(env, &global);
napi_value key = nullptr;
napi_create_string_utf8(env, attributes[i * 4 + 2].c_str(), // 4 and 2: number of args
attributes[i * 4 + 2].size(), &key); // 4 and 2: number of args
napi_value value = nullptr;
napi_create_string_utf8(env, attributes[i * 4 + 3].c_str(), // 4 and 3: number of args
attributes[i * 4 + 3].size(), &value); // 3 and 4: number of args
napi_value argv[3] = {key, value, thisVar};
napi_call_function(env, global, attrFunc_, argc, argv, &returnVal);
bool bRec = false;
napi_get_value_bool(env, returnVal, &bRec);
// return bRec; //将此行代码注释
// 添加以下代码即可
if (!bRec) {
return bRec;
}
}
return true;
}
通过对比OpenHarmony 3.1 Release和master分支编译的系统发现,在master分支中解析xml标签属性是正常的,3.1release只会解析标签上的第一个属性,找到源码中(base/compileruntime/js_api_module/xml/js_xml.cpp)关于xml解析的代码进行对比发现有以下的不同:
bool XmlPullParser::ParseAttri(napi_env env, napi_value thisVar) const
{
for (size_t i = 0; i < attriCount_; ++i) {
napi_value returnVal = nullptr;
size_t argc = 3; // 3: number of args
napi_value global = nullptr;
napi_get_global(env, &global);
napi_value key = nullptr;
napi_create_string_utf8(env, attributes[i * 4 + 2].c_str(), // 4 and 2: number of args
attributes[i * 4 + 2].size(), &key); // 4 and 2: number of args
napi_value value = nullptr;
napi_create_string_utf8(env, attributes[i * 4 + 3].c_str(), // 4 and 3: number of args
attributes[i * 4 + 3].size(), &value); // 3 and 4: number of args
napi_value argv[3] = {key, value, thisVar};
napi_call_function(env, global, attrFunc_, argc, argv, &returnVal);
bool bRec = false;
napi_get_value_bool(env, returnVal, &bRec);
// 3.1release 直接返回bRec
//return bRec;
// master 判断后返回
if (!bRec) {
return bRec;
}
}
return true;
}
void XmlPullParser::Parse(napi_env env, napi_value thisVar)
{
if (tagFunc_ || attrFunc_ || tokenFunc_) {
while (type != TagEnum::END_DOCUMENT) {
ParseOneTag();
bool bRec = false;
if (tagFunc_ && type == TagEnum::START_TAG) {
napi_value returnVal = nullptr;
size_t argc = 3; // 3: number of args
napi_value global = nullptr;
napi_get_global(env, &global);
napi_value key = nullptr;
napi_create_string_utf8(env, name_.c_str(), name_.size(), &key);
napi_value value = nullptr;
napi_create_string_utf8(env, text_.c_str(), text_.size(), &value);
napi_value argv[3] = {key, value, thisVar};
napi_call_function(env, global, tagFunc_, argc, argv, &returnVal);
napi_get_value_bool(env, returnVal, &bRec);
}
if (tagFunc_ && type == TagEnum::START_TAG && !bRec) {
break;
}
if (attrFunc_ && attriCount_) {
bRec = ParseAttri(env, thisVar);
// 3.1release中无下一行代码,master中存在
attriCount_ = 0;
}
if (attrFunc_ && attriCount_ && !bRec) {
break;
}
if (tokenFunc_) {
bRec = ParseToken(env, thisVar);
}
if (tokenFunc_ && !bRec) {
break;
}
}
}
}
// 3.1release
bool XmlPullParser::ParseTagValueFunc(char c, bool bFlag, TextEnum textEnum, size_t &start, std::string& result)
// master
bool XmlPullParser::ParseTagValueFunc(char &c, bool bFlag, TextEnum textEnum, size_t &start, std::string &result)
// 3.1release
std::string XmlPullParser::ParseTagValue(char delimiter, bool resolveEntities,
bool throwOnResolveFailure, TextEnum textEnum)
{
size_t start = position_;
std::string result = " ";
if (textEnum == TextEnum::TEXT && text_ != "") {
result.append(text_);
}
while (true) {
size_t iRecv = ParseTagValueInner(start, result, delimiter, textEnum, resolveEntities);
if (iRecv == 0) {
return result;
} else if (iRecv == 1) {
break;
} else if (iRecv == 2) { // 2: break flag
continue;
} else if (!ParseTagValueFunc(static_cast<char>(iRecv), throwOnResolveFailure, textEnum, start, result)) {
continue;
}
++position_;
result = result + static_cast<char>(iRecv);
start = position_;
}
result.append(strXml_, start, position_ - start);
return result;
}
// master
std::string XmlPullParser::ParseTagValue(char delimiter, bool resolveEntities, bool throwOnResolveFailure, TextEnum textEnum)
{
size_t start = position_;
std::string result = "";
if (textEnum == TextEnum::TEXT && text_ != "") {
result.append(text_);
}
while (true) {
char cRecv = static_cast<char>(ParseTagValueInner(start, result, delimiter, textEnum, resolveEntities));
if (cRecv == 0) {
return result;
} else if (cRecv == 1) {
break;
} else if (cRecv == 2) { // 2: break flag
continue;
} else if (!ParseTagValueFunc(cRecv, throwOnResolveFailure, textEnum, start, result)) {
continue;
}
++position_;
result = result + static_cast<char>(cRecv);
start = position_;
}
result.append(strXml_, start, position_ - start);
return result;
}
// 3.1release
void XmlPullParser::ParseNspFunc(size_t &i, std::string &attrName, bool &any)
// master
void XmlPullParser::ParseNspFunc(size_t &i, const std::string &attrName, bool &any)
bool XmlPullParser::ParseNsp()
{
...
// 3.1release中存在此if判断,master中没有
if (namespace_ == "") {
namespace_ = "";
}
...
}
bool XmlPullParser::ParseNsp()
{
...
// 3.1release中存在此if判断,master中没有
if (namespace_ == "") {
namespace_ = "";
}
...
}
void XmlPullParser::ParseEntityDecl()
{
...
// master分支中添加了此if代码,3.1release没有
if (generalEntity && bDocDecl) {
documentEntities[name] = entityValue;
}
...
}
通过对比分析,与xml标签属性解析相关的有第1处和第2处,其余不同的地方均是代码写法上的优化,未改变相关逻辑,在3.1release代码中分别修改1、2处的代码编译后测试,修改第一处代码即可对xml的所有属性进行解析。
在新的版本中可能已经修复了一些问题,合理的对比不同分支的代码可以更快的了解和解决问题。