戰(zhàn):基于 SAX 事件回調(diào)解析 XML(@nativescript/core/xml))
【免費(fèi)下載鏈接】NativeScript? Write Native with TypeScript ? Best of all worlds (TypeScript, Swift, Objective C, Kotlin, Java, Dart). Use what you love ?? Angular, React, Solid, Svelte, Vue with: iOS (UIKit, SwiftUI), Android (View, Jetpack Compose), Flutter and you name it compatible.項(xiàng)目地址https://gitcode.com/gh_mirrors/na/NativeScript點(diǎn)擊查看免費(fèi)下載本文圍繞 NativeScript 核心包中的nativescript/core/xml模塊展開(kāi)系統(tǒng)講解如何使用其XmlParser一個(gè)基于 easysax 實(shí)現(xiàn)的非驗(yàn)證型 SAX 解析器以事件驅(qū)動(dòng)方式解析 XML 字符串。你將掌握模塊引入方式、ParserEventType五種事件類型、ParserEvent事件對(duì)象的完整字段、錯(cuò)誤回調(diào)、實(shí)體引用自動(dòng)解碼、命名空間處理以及底層解析原理與自動(dòng)化測(cè)試的驗(yàn)證方式。文中所有代碼與結(jié)論均來(lái)自當(dāng)前倉(cāng)庫(kù)的官方 How-To 文檔、源碼實(shí)現(xiàn)與測(cè)試用例可直接復(fù)制使用。從文檔到源碼Xml 模塊的定位apps/automated/src/xml-parser-tests/xml-parser.md是 NativeScript 官方文檔體系中關(guān)于 Xml 模塊的 How-To 入口文檔元數(shù)據(jù)中標(biāo)注title: xml、description: Examples for using xml其正文由兩個(gè)代碼片段構(gòu)成xml-module-snippet引入模塊與xml-parser-snippet解析 XML兩個(gè)片段的實(shí)際代碼分別定義在 xml-parser-tests.ts 和 xml-parser-tests.ts 中——NativeScript 的文檔采用片段即測(cè)試機(jī)制文檔引用的示例代碼本身就是可執(zhí)行的自動(dòng)化測(cè)試從而保證文檔示例永遠(yuǎn)與實(shí)現(xiàn)一致。模塊的真實(shí)實(shí)現(xiàn)位于 packages/core/xml/index.ts而 packages/core/xml/Readme.md 給出了準(zhǔn)確定位Contains the XmlParser class, which is a SAX parser using the easysax implementation.也就是說(shuō)XmlParser是一個(gè)使用 easysax 實(shí)現(xiàn)的 SAX 解析器與一次性構(gòu)建整棵對(duì)象樹(shù)的 DOM 解析不同SAX 解析在掃描 XML 文本的過(guò)程中邊讀取邊觸發(fā)事件內(nèi)存占用低、速度快非常適合解析結(jié)果需要即時(shí)消費(fèi)的場(chǎng)景如 NativeScript 的 UI 模板解析。引入 Xml 模塊官方 How-To 片段xml-module-snippet展示了最基礎(chǔ)的引入方式CommonJSvar xmlModule require(nativescript/core/xml);在 TypeScript 項(xiàng)目中更推薦使用 ES 模塊導(dǎo)入與自動(dòng)化測(cè)試 xml-parser-tests.ts 一致import * as xmlModule from nativescript/core/xml;引入后即可使用三個(gè)核心構(gòu)件XmlParser—— SAX 解析器類ParserEventType—— 事件類型常量類ParserEvent—— 事件對(duì)象類。解析 XML事件驅(qū)動(dòng)回調(diào)官方片段xml-parser-snippet即測(cè)試函數(shù)test_XmlParser_DummyDocumentationTest中的完整示例給出了解析 XML 的標(biāo)準(zhǔn)姿勢(shì)構(gòu)造XmlParser時(shí)傳入事件回調(diào)onEventCallback與錯(cuò)誤回調(diào)onErrorCallback然后調(diào)用parse(xmlString)開(kāi)始解析var onEventCallback function (event: xmlModule.ParserEvent) { switch (event.eventType) { case xmlModule.ParserEventType.StartElement: var message event.eventType event.elementName; if (event.attributes) { message , Attributes:; for (var attributeName in event.attributes) { if (event.attributes.hasOwnProperty(attributeName)) { message attributeName event.attributes[attributeName] ; } } } //console.log(message); break; case xmlModule.ParserEventType.EndElement: //console.log(event.eventType event.elementName); break; case xmlModule.ParserEventType.Text: var significantText event.data.trim(); if (significantText ! ) { //console.log(event.eventType \ significantText \); } break; } }; var onErrorCallback function (error: Error) { console.log(Error: error.message); }; var xmlParser new xmlModule.XmlParser(onEventCallback, onErrorCallback); xmlParser.parse(DocumentFirst attr1attribute1 attr2attribute2I am first/FirstSecondI am second/Second/Document);官方注釋明確給出了這段代碼的預(yù)期控制臺(tái)輸出可以作為自測(cè)基準(zhǔn)StartElement Document StartElement First, Attributes: attr1 attribute1 attr2 attribute2 Text I am first EndElement First StartElement Second Text I am second EndElement Second EndElement Document注意示例中的處理技巧Text事件先用trim()過(guò)濾掉文檔格式化產(chǎn)生的空白字符換行、縮進(jìn)只對(duì)有效文本做處理StartElement事件中先判斷event.attributes是否存在再遍歷屬性這是因?yàn)闊o(wú)屬性的元素不會(huì)上報(bào)屬性見(jiàn)下文測(cè)試驗(yàn)證。ParserEventType五種事件類型ParserEventType定義在 index.ts是一個(gè)靜態(tài)常量類事件類型為字符串字面量常量值觸發(fā)時(shí)機(jī)ParserEventType.StartElementStartElement遇到元素開(kāi)始標(biāo)簽ParserEventType.EndElementEndElement遇到元素結(jié)束標(biāo)簽ParserEventType.TextText元素內(nèi)的文本內(nèi)容ParserEventType.CDATACDATA遇到![CDATA[...]]塊ParserEventType.CommentComment遇到!-- ... --注釋從集成測(cè)試資源 xml.xml 與預(yù)期輸出 xml.expected 可以看到CDATA 與 Comment 都會(huì)獨(dú)立產(chǎn)生事件CDATA 內(nèi)的 JavaScript 代碼片段、多行注釋均以data形式原樣交付且事件序列嚴(yán)格按文檔順序排列。ParserEvent事件對(duì)象詳解每次事件觸發(fā)時(shí)回調(diào)收到的ParserEvent對(duì)象定義在 index.ts包含以下字段屬性類型說(shuō)明eventTypestring事件類型取值為ParserEventType五個(gè)成員之一positionPosition事件在 XML 字符串中的位置{ line, column }均從 1 開(kāi)始計(jì)數(shù)prefixstring開(kāi)啟命名空間處理后元素的前綴如a1:Element中的a1僅 StartElement / EndElement 有效namespacestring開(kāi)啟命名空間處理后解析出的命名空間 URI僅 StartElement / EndElement 有效elementNamestring元素名開(kāi)啟命名空間處理時(shí)為去除前綴后的本地名僅 StartElement / EndElement 有效attributesObjectStartElement 事件的屬性字典無(wú)屬性時(shí)該值為undefineddatastringText / CDATA / Comment 事件攜帶的文本數(shù)據(jù)toString()string返回該事件的 JSON 字符串表示含全部字段其中position的精確行號(hào)與列號(hào)定位能力使開(kāi)發(fā)者可以在出錯(cuò)或調(diào)試時(shí)快速回溯到 XML 原文的對(duì)應(yīng)位置toString()則為日志與斷言提供了結(jié)構(gòu)化輸出集成測(cè)試正是依賴它逐字符比對(duì)事件序列。XmlParser的構(gòu)造簽名見(jiàn) index.ts為constructor(onEvent: (event: ParserEvent) void, onError?: (error: Error, position: Position) void, processNamespaces?: boolean)三個(gè)參數(shù)的含義onEvent必填每個(gè)解析事件都會(huì)調(diào)用onError可選解析出錯(cuò)時(shí)調(diào)用回調(diào)同時(shí)收到Error對(duì)象與出錯(cuò)位置positionprocessNamespaces可選是否啟用命名空間處理默認(rèn)不啟用。錯(cuò)誤處理畸形 XML 會(huì)觸發(fā) onError當(dāng) XML 結(jié)構(gòu)非法時(shí)例如開(kāi)始標(biāo)簽與結(jié)束標(biāo)簽不匹配解析器不會(huì)拋出未捕獲異常而是調(diào)用onErrorCallback。實(shí)現(xiàn)位于 index.tsif (onError) { this._parser.on(error, function (msg, pos) { onError(new Error(msg), pos()); }); }對(duì)應(yīng)測(cè)試test_XmlParser_OnErrorIsCalledWhenAnErrorOccursxml-parser-tests.ts用element/otherElement這種標(biāo)簽錯(cuò)配的輸入驗(yàn)證了錯(cuò)誤回調(diào)必然被調(diào)用。同時(shí)注意如果構(gòu)造時(shí)未傳入onError則錯(cuò)誤回調(diào)不會(huì)被注冊(cè)——因此生產(chǎn)代碼建議始終提供錯(cuò)誤回調(diào)。實(shí)體引用自動(dòng)解碼XmlParser會(huì)對(duì)文本內(nèi)容與屬性值中的實(shí)體引用自動(dòng)解碼無(wú)需開(kāi)發(fā)者手動(dòng)處理。核心正則定義在 index.tsconst _entitySearchRegEx /#(\d);|#x([0123456789abcdef]);|(\w);/gi;它覆蓋三類實(shí)體十進(jìn)制數(shù)值實(shí)體#38;形式十六進(jìn)制數(shù)值實(shí)體#x26;形式命名實(shí)體lt;、gt;、quot;、amp;、apos;等由一個(gè)覆蓋數(shù)百個(gè)命名實(shí)體的大映射表_generateAmpMap含 Latin-1、希臘字母、標(biāo)點(diǎn)、貨幣符號(hào)等解析未知命名實(shí)體按原樣保留。測(cè)試用例給出了完整的驗(yàn)證矩陣文本內(nèi)容解碼xml-parser-tests.tselementlt;gt;quot;amp;apos;/element解析出文本屬性值解碼xml-parser-tests.tsLabel textlt;gt;quot;amp;apos;/中屬性text的值為Unicode 實(shí)體xml-parser-tests.ts#x1f923;#x2713;被正確解碼為 emoji 與 ?文本與屬性值均適用。從源碼看屬性值在startNode事件中逐屬性調(diào)用_dereferenceEntities解碼index.ts文本內(nèi)容則先解碼實(shí)體再交給回調(diào)index.ts。命名空間處理當(dāng)構(gòu)造時(shí)傳入第三個(gè)參數(shù)trueprocessNamespaces時(shí)解析器會(huì)維護(hù)一個(gè)命名空間棧對(duì)元素的前綴進(jìn)行解析并在事件中暴露prefix與namespace字段。相關(guān)實(shí)現(xiàn)包括_getNamespacesStackEntryindex.ts收集元素的xmlns/xmlns:xx屬性構(gòu)建當(dāng)前作用域的命名空間映射_resolveNamespaceindex.ts將prefix:name形式的元素名拆分為前綴與本地名并從命名空間棧頂向下查找最近聲明的前綴綁定棧的壓入與彈出StartElement 時(shí)壓入、EndElement 時(shí)彈出index.tsparse開(kāi)始時(shí)棧被重置index.ts。測(cè)試資源 xml-with-namespaces.xml 演示了完整的命名空間語(yǔ)義Element xmlnshttp://a-default xmlns:a1http://a1 xmlns:a2http://a2 xmlns:duplicatehttp://a-duplicate expected-namespacehttp://a-default Element expected-namespacehttp://a-default/ a1:Element expected-namespacehttp://a1/ a2:Element expected-namespacehttp://a2/ Element xmlnshttp://b-default xmlns:b1http://b1 xmlns:b2http://b2 xmlns:duplicatehttp://b-duplicate expected-namespacehttp://b-default ...對(duì)應(yīng)測(cè)試test_XmlParser_NamespacesTestxml-parser-tests.ts對(duì)每個(gè) StartElement 斷言event.namespace等于其expected-namespace屬性。該用例至少驗(yàn)證了三個(gè)關(guān)鍵行為默認(rèn)命名空間無(wú)前綴元素解析為最近聲明的默認(rèn)命名空間http://a-default/http://b-default前綴綁定a1:Element解析為http://a1b1:Element解析為http://b1前綴遮蔽shadowing內(nèi)層元素重新聲明duplicate前綴后其解析結(jié)果從外層的http://a-duplicate變?yōu)閮?nèi)層的http://b-duplicate——這正是命名空間棧從頂向下查找設(shè)計(jì)的意義。底層原理EasySAX 非驗(yàn)證型 SAX 解析器XmlParser內(nèi)部將工作委托給EasySAXParser實(shí)例化于 index.ts類型聲明見(jiàn) easysax.d.ts源碼注釋明確標(biāo)注其來(lái)源與版本A simple non-validating SAX parser based on easysax version 0.1.14該第三方庫(kù)以純 JavaScript 實(shí)現(xiàn)easysax.js其自帶說(shuō)明 README.md 揭示了設(shè)計(jì)取向這是一個(gè)只解析需要的、盡可能快的 SAX 風(fēng)格解析器非流式、要求整個(gè) XML 一次性載入內(nèi)存不適合處理巨型文件并內(nèi)置了命名空間處理機(jī)制——這與XmlParser的 API 設(shè)計(jì)完全吻合parse(xmlString)接收完整字符串事件回調(diào)同步觸發(fā)。XmlParser在EasySAXParser之上做了四層封裝將 easysax 的startNode/textNode/endNode/cdata/comment/error原生事件轉(zhuǎn)換為統(tǒng)一的ParserEvent對(duì)象含position定位修復(fù)底層細(xì)節(jié)easysax 在元素?zé)o屬性時(shí)會(huì)返回字面量trueXmlParser將其歸一化為undefined見(jiàn) index.ts統(tǒng)一完成實(shí)體引用的解碼文本與屬性值在需要時(shí)疊加命名空間棧解析。此外XmlParser還暴露了一個(gè)angularSyntax布爾屬性getter/setter 透?jìng)鞯降讓咏馕銎饕?jiàn) index.ts用于控制對(duì) Angular 風(fēng)格模板語(yǔ)法的解析行為這說(shuō)明該解析器在 NativeScript 生態(tài)中同時(shí)承擔(dān)著框架模板解析的底層職責(zé)。測(cè)試驗(yàn)證與實(shí)戰(zhàn)集成單元級(jí)行為驗(yàn)證apps/automated/src/xml-parser-tests/xml-parser-tests.ts 通過(guò)TKUnit斷言框架覆蓋了本文前述的所有行為可歸納為一張驗(yàn)證清單測(cè)試函數(shù)驗(yàn)證點(diǎn)test_XmlParser_IsDefined/test_ParserEventType_IsDefinedXmlParser與ParserEventType均可用test_XmlParser_ElementsWithoutAttributesDoNotReportThem無(wú)屬性元素的attributes為undefinedtest_XmlParser_EntityReferencesAreDecoded文本內(nèi)命名實(shí)體解碼test_XmlParser_EntityReferencesInAttributeValuesAreDecoded屬性值內(nèi)命名實(shí)體解碼test_XmlParser_UnicodeEntitiesAreDecoded文本內(nèi)十六進(jìn)制 Unicode 實(shí)體解碼test_XmlParser_UnicodeEntitiesInAttributeValuesAreDecoded屬性值內(nèi)十六進(jìn)制 Unicode 實(shí)體解碼test_XmlParser_OnErrorIsCalledWhenAnErrorOccurs標(biāo)簽錯(cuò)配觸發(fā)錯(cuò)誤回調(diào)test_XmlParser_IntegrationTest用 xml.xml 解析并與 xml.expected 逐字符比對(duì)跳過(guò)空白 Texttest_XmlParser_NamespacesTest命名空間解析與前綴遮蔽test_MultiParserTemplate以 XML 字符串驅(qū)動(dòng) UI 構(gòu)建其中集成測(cè)試xml-parser-tests.ts最有參考價(jià)值它從應(yīng)用資源中讀取真實(shí) XML 文件、用XmlParser解析、將每個(gè)非空白事件序列化為字符串再與官方預(yù)期的 JSON 事件流逐字符比對(duì)——這份 xml.expected 本身就是一個(gè)極佳的事件流教學(xué)樣例展示了屬性、嵌套元素、混合內(nèi)容Pre-Text Inline.../Inline Post-text.、實(shí)體、CDATA、注釋在事件序列中的真實(shí)形態(tài)。與 UI 構(gòu)建器的集成test_MultiParserTemplatexml-parser-tests.ts展示了 XML 解析在 NativeScript 中最典型的業(yè)務(wù)場(chǎng)景——UI 模板解析它加載 itemTemplates.xml一個(gè)包含TabView、ListView.itemTemplates與template keyfoo的完整頁(yè)面片段交給nativescript/core/ui/builder的Builder.parse直接生成視圖對(duì)象并斷言items長(zhǎng)度為 1。這印證了掌握XmlParser的事件模型也就理解了 NativeScript 聲明式 UI 模板解析機(jī)制的底層基礎(chǔ)。小結(jié)nativescript/core/xml的XmlParser為 NativeScript 應(yīng)用提供了輕量、同步、事件驅(qū)動(dòng)的 XML 解析能力事件類型只有五種StartElement/EndElement/Text/CDATA/Comment事件對(duì)象ParserEvent攜帶類型、位置、元素名、屬性、文本等結(jié)構(gòu)化信息文本與屬性中的實(shí)體引用含 Unicode 實(shí)體自動(dòng)解碼錯(cuò)誤通過(guò)可選回調(diào)上報(bào)通過(guò)processNamespaces參數(shù)可啟用完整的命名空間解析含默認(rèn)命名空間與前綴遮蔽底層基于非流式、非驗(yàn)證型的 easysax 解析器要求 XML 整體載入內(nèi)存適合 UI 模板、配置文件等中小規(guī)模文檔的即時(shí)解析。如需繼續(xù)深入可直接研讀實(shí)現(xiàn)源碼 packages/core/xml/index.ts、底層庫(kù) packages/core/js-libs/easysax/easysax.js以及測(cè)試與文檔三件套 xml-parser-tests.ts、xml-parser.md 和 xml-with-namespaces.xml。贊分享【免費(fèi)下載鏈接】NativeScript? Write Native with TypeScript ? Best of all worlds (TypeScript, Swift, Objective C, Kotlin, Java, Dart). Use what you love ?? Angular, React, Solid, Svelte, Vue with: iOS (UIKit, SwiftUI), Android (View, Jetpack Compose), Flutter and you name it compatible.項(xiàng)目地址https://gitcode.com/gh_mirrors/na/NativeScript點(diǎn)擊查看免費(fèi)下載相關(guān)推薦Kubernetes Contributor Summit 內(nèi)容策劃完全指南Events Content 子團(tuán)隊(duì)角色體系與實(shí)戰(zhàn)手冊(cè)解析Kubernetes Contributor Summit 內(nèi)容策劃完全指南Events Content 子團(tuán)隊(duì)角色體系與實(shí)戰(zhàn)手冊(cè)解析 導(dǎo)讀 本指南以 KubFeign SAX Decoder 實(shí)戰(zhàn)指南用 SAX 流式解析 XML 響應(yīng)Feign SAX Decoder 實(shí)戰(zhàn)指南用 SAX 流式解析 XML 響應(yīng) 導(dǎo)讀 feign sax 是 Feign 生態(tài)中專門用于 XML 響應(yīng)解碼的模后端API設(shè)計(jì)TBOOX/TBOX XML讀取器SAX風(fēng)格的流式XML解析TBOOX/TBOX XML讀取器SAX風(fēng)格的流式XML解析 引言告別內(nèi)存瓶頸擁抱流式XML解析 在傳統(tǒng)XML處理中DOMDocument Objec后端上一篇Gradle Doctor終極指南快速解決Android構(gòu)建中的Jetifier警告與多模塊項(xiàng)目?jī)?yōu)化下一篇大麥網(wǎng)搶票腳本到底怎么買到票創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考