From 43e65884488f9a8c039e26a552893d38c17e94ed Mon Sep 17 00:00:00 2001 From: Orange_66 Date: Tue, 9 Sep 2025 17:01:47 +0800 Subject: [PATCH] Add a callback function to parse xml attributes Issue: https://gitee.com/openharmony/arkcompiler_runtime_core/issues/ICX5S6 Signed-off-by: Orange_66 --- static_core/plugins/ets/sdk/api/@ohos.xml.ets | 9 +++-- .../ets/sdk/native/api/ani_xmlpullparser.cpp | 36 +++++++++++++++---- .../ets/sdk/native/api/ani_xmlpullparser.h | 8 +++-- static_core/plugins/ets/sdk/native/main.cpp | 4 ++- .../api/@ohos/xml/XmlPullParserTest2.ets | 28 +++++++++++++++ 5 files changed, 73 insertions(+), 12 deletions(-) diff --git a/static_core/plugins/ets/sdk/api/@ohos.xml.ets b/static_core/plugins/ets/sdk/api/@ohos.xml.ets index 2312da897a..4223109b2b 100644 --- a/static_core/plugins/ets/sdk/api/@ohos.xml.ets +++ b/static_core/plugins/ets/sdk/api/@ohos.xml.ets @@ -32,6 +32,8 @@ function createBusinessError(code: int, message: string) { export namespace xml { + export type AttributeWithTagCb = (tagName: string, key: string, value: string) => boolean + export enum EventType { START_DOCUMENT, END_DOCUMENT, @@ -89,6 +91,7 @@ export namespace xml { supportDoctype?: boolean tagValueCallbackFunction?: (name: string, value: string) => boolean tokenValueCallbackFunction?: (eventType: EventType, value: ParseInfo) => boolean + attributeWithTagCallbackFunction?: AttributeWithTagCb } export class XmlPullParser { @@ -544,7 +547,8 @@ export namespace xml { option.supportDoctype ?? false, option.attributeValueCallbackFunction, option.tagValueCallbackFunction, - option.tokenValueCallbackFunction + option.tokenValueCallbackFunction, + option.attributeWithTagCallbackFunction ); } @@ -555,7 +559,8 @@ export namespace xml { supportDoctype: boolean, attributeValueCallbackFunction?: (name: string, value: string) => boolean, tagValueCallbackFunction?: (name: string, value: string) => boolean, - tokenValueCallbackFunction?: (eventType: EventType, value: ParseInfo) => boolean + tokenValueCallbackFunction?: (eventType: EventType, value: ParseInfo) => boolean, + attributeWithTagCallbackFunction?: AttributeWithTagCb ): boolean; private static native parserErrorInfo(pointer: long): string; diff --git a/static_core/plugins/ets/sdk/native/api/ani_xmlpullparser.cpp b/static_core/plugins/ets/sdk/native/api/ani_xmlpullparser.cpp index 30c8dfb2f5..4cebd2b63a 100644 --- a/static_core/plugins/ets/sdk/native/api/ani_xmlpullparser.cpp +++ b/static_core/plugins/ets/sdk/native/api/ani_xmlpullparser.cpp @@ -160,7 +160,7 @@ XmlPullParser::~XmlPullParser() // CC-OFFNXT(G.FUN.01-CPP) options of parse ani_boolean XmlPullParser::ParseXml(ani_env *env, [[maybe_unused]] ani_class self, ani_long pointer, ani_boolean ignoreNS, ani_boolean supportDCT, ani_fn_object attrValCb, - ani_fn_object tagValCb, ani_fn_object tknCalCb) + ani_fn_object tagValCb, ani_fn_object tknCalCb, ani_fn_object attrTagCb) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) CHECK_NON_NULL_PARSER_AND_RETURN(pointer, false); @@ -170,6 +170,7 @@ ani_boolean XmlPullParser::ParseXml(ani_env *env, [[maybe_unused]] ani_class sel that->attrFunc_ = attrValCb; that->tagFunc_ = tagValCb; that->tokenFunc_ = tknCalCb; + that->attrWithTagFunc_ = attrTagCb; that->Parse(env); return static_cast(that->xmlPullParserError_.empty()); } @@ -266,14 +267,23 @@ bool XmlPullParser::ParseToken(ani_env *env) const return static_cast(UnboxToBoolean(env, static_cast(returnVal))); } -bool XmlPullParser::ParseAttr(ani_env *env) const +bool XmlPullParser::ParseAttr(ani_env *env, ani_fn_object attriFun) const { for (size_t i = 0; i < attrCount_; ++i) { ani_string key = CreateStringUtf8(env, attributes_[i * 4 + 2]); // 4 and 2: number of args ani_string value = CreateStringUtf8(env, attributes_[i * 4 + 3]); // 4 and 3: number of args - std::vector argv {key, value}; ani_ref returnVal {}; - env->FunctionalObject_Call(attrFunc_, argv.size(), argv.data(), &returnVal); + std::vector argv {}; + if (attriFun == attrFunc_) { + argv.push_back(key); + argv.push_back(value); + } else { + ani_string tagName = CreateStringUtf8(env, name_); + argv.push_back(tagName); + argv.push_back(key); + argv.push_back(value); + } + env->FunctionalObject_Call(attriFun, argv.size(), argv.data(), &returnVal); if (!static_cast(UnboxToBoolean(env, static_cast(returnVal)))) { return false; } @@ -298,6 +308,16 @@ bool XmlPullParser::HandleTokenFunc(ani_env *env) return ParseToken(env); } +bool XmlPullParser::HandleAttrWithTagFunc(ani_env *env) +{ + if (!(attrWithTagFunc_ && attrCount_)) { + return true; + } + bool bRec = ParseAttr(env, attrWithTagFunc_); + attrCount_ = 0; + return bRec; +} + /** * This function will be deprecated in the future due to a bug. * After parsing the data, since the variable attrCount_ was reset to 0, @@ -308,7 +328,7 @@ bool XmlPullParser::HandleAttrFunc(ani_env *env) if (IsNullishValue(env, static_cast(attrFunc_)) || attrCount_ == 0U) { return true; } - bool bRec = ParseAttr(env); + bool bRec = ParseAttr(env, attrFunc_); attrCount_ = 0; return bRec; } @@ -318,7 +338,8 @@ void XmlPullParser::Parse(ani_env *env) bool tagFuncIsNull = IsNullishValue(env, static_cast(tagFunc_)); bool attrFuncIsNull = IsNullishValue(env, static_cast(attrFunc_)); bool tokenFuncIsNull = IsNullishValue(env, static_cast(tokenFunc_)); - if (tagFuncIsNull && attrFuncIsNull && tokenFuncIsNull) { + bool attrTagFuncIsNull = IsNullishValue(env, static_cast(attrWithTagFunc_)); + if (tagFuncIsNull && attrFuncIsNull && tokenFuncIsNull && attrTagFuncIsNull) { return; } while (type_ != TagEnum::END_DOCUMENT) { @@ -331,6 +352,9 @@ void XmlPullParser::Parse(ani_env *env) if (!tokenFuncIsNull && !HandleTokenFunc(env)) { break; } + if (!attrTagFuncIsNull && !HandleAttrWithTagFunc(env)) { + break; + } if (!attrFuncIsNull && !HandleAttrFunc(env)) { break; } diff --git a/static_core/plugins/ets/sdk/native/api/ani_xmlpullparser.h b/static_core/plugins/ets/sdk/native/api/ani_xmlpullparser.h index 2d5c53a803..5e0aa31ae4 100644 --- a/static_core/plugins/ets/sdk/native/api/ani_xmlpullparser.h +++ b/static_core/plugins/ets/sdk/native/api/ani_xmlpullparser.h @@ -53,9 +53,9 @@ public: static ani_long BindNative(ani_env *env, ani_class self, ani_string content); static ani_boolean ReleaseNative(ani_env *env, ani_class self, ani_long pointer); // CC-OFFNXT(G.FUN.01-CPP) options of parse - static ani_boolean ParseXml(ani_env *env, ani_class self, ani_long pointer, ani_boolean ignoreNS, + static ani_boolean ParseXml(ani_env *env, [[maybe_unused]] ani_class self, ani_long pointer, ani_boolean ignoreNS, ani_boolean supportDCT, ani_fn_object attrValCb, ani_fn_object tagValCb, - ani_fn_object tknCalCb); + ani_fn_object tknCalCb, ani_fn_object attrTagCb); static ani_ref GetParseError(ani_env *env, ani_class self, ani_long pointer); private: @@ -153,10 +153,11 @@ private: void ParseCdect(); bool ParseTag(ani_env *env) const; - bool ParseAttr(ani_env *env) const; + bool ParseAttr(ani_env *env, ani_fn_object attriFun) const; bool ParseToken(ani_env *env) const; bool HandleTagFunc(ani_env *env); bool HandleTokenFunc(ani_env *env); + bool HandleAttrWithTagFunc(ani_env *env); bool HandleAttrFunc(ani_env *env); void ParseNspFunction(); @@ -182,6 +183,7 @@ private: ani_fn_object tagFunc_ {nullptr}; ani_fn_object attrFunc_ {nullptr}; ani_fn_object tokenFunc_ {nullptr}; + ani_fn_object attrWithTagFunc_ {nullptr}; std::string strXml_ {}; std::string prefix_ {}; diff --git a/static_core/plugins/ets/sdk/native/main.cpp b/static_core/plugins/ets/sdk/native/main.cpp index c4fcc8ce75..dffc33d9be 100644 --- a/static_core/plugins/ets/sdk/native/main.cpp +++ b/static_core/plugins/ets/sdk/native/main.cpp @@ -293,7 +293,9 @@ static ani_status BindXmlPullParser(ani_env *env) std::array methods = { ani_native_function {"bindNative", "C{std.core.String}:l", reinterpret_cast(XmlPullParser::BindNative)}, ani_native_function {"releaseNative", "l:z", reinterpret_cast(XmlPullParser::ReleaseNative)}, - ani_native_function {"parseXmlInner", "lzzC{std.core.Function2}C{std.core.Function2}C{std.core.Function2}:z", + ani_native_function {"parseXmlInner", + "lzzC{std.core.Function2}C{std.core.Function2}C{std.core.Function2}\ + C{std.core.Function3}:z", reinterpret_cast(XmlPullParser::ParseXml)}, ani_native_function {"parserErrorInfo", "l:C{std.core.String}", reinterpret_cast(XmlPullParser::GetParseError)}, diff --git a/static_core/plugins/ets/tests/ets_sdk/api/@ohos/xml/XmlPullParserTest2.ets b/static_core/plugins/ets/tests/ets_sdk/api/@ohos/xml/XmlPullParserTest2.ets index 59b8a2795e..954778a993 100644 --- a/static_core/plugins/ets/tests/ets_sdk/api/@ohos/xml/XmlPullParserTest2.ets +++ b/static_core/plugins/ets/tests/ets_sdk/api/@ohos/xml/XmlPullParserTest2.ets @@ -13,9 +13,11 @@ * limitations under the License. */ import {xml} from "@ohos.xml" +import {util} from "@ohos.util" function main(): int { const suite = new arktest.ArkTestsuite("XmlPullParser API tests, part2"); + suite.addTest("Testing XML PullParser with attributeWithTagCallbackFunction as function.", testXmlPullParserParseOptions0010) suite.addTest("Testing XML PullParser with tokenValueCallbackFunction as undefined.", testXmlPullParserParseOptions0009) suite.addTest("Testing XML PullParser with tokenValueCallbackFunction as function.", testXmlPullParserParseOptions0008) suite.addTest("Testing XML PullParser with tagValueCallbackFunction as function.", testXmlPullParserParseOptions0006) @@ -478,3 +480,29 @@ function testXmlPullParserParseOptions0009() { } } +function testXmlPullParserParseOptions0010() { + console.log("orange: test start"); + let xmlStr = + '' + + '' + + '' + + ''; + let textEncoder = new util.TextEncoder(); + let arrBuffer = textEncoder.encodeInto(xmlStr); + let that = new xml.XmlPullParser(arrBuffer.buffer as object as ArrayBuffer, 'UTF-8'); + + let attrWithTag = (tagName: string, key: string, value: string): boolean => { + if (tagName == "orange") { + console.log("value = " + value); + } + return true; + } + + let options: xml.ParseOptions = { + supportDoctype: true, + ignoreNameSpace: true, + attributeWithTagCallbackFunction:attrWithTag + }; + that.parseXml(options); +} + -- Gitee