2 changed files with 122 additions and 17 deletions
@ -0,0 +1,74 @@ |
|||||||
|
import 'dart:convert'; |
||||||
|
import 'dart:io'; |
||||||
|
import 'package:xml/xml.dart'; |
||||||
|
|
||||||
|
class FastXmlParser { |
||||||
|
/// 批量解析XML文件根节点属性 |
||||||
|
static Future<List<Map<String, String>>> batchParse( |
||||||
|
List<String> filePaths, { |
||||||
|
int maxFastParseBytes = 1024, |
||||||
|
}) async { |
||||||
|
return await Future.wait(filePaths.map((path) => _parseWithFallback(path, maxFastParseBytes))); |
||||||
|
} |
||||||
|
|
||||||
|
static Future<Map<String, String>> parse(String filePath, {int maxFastParseBytes = 512}) async { |
||||||
|
return _parseWithFallback(filePath, maxFastParseBytes); |
||||||
|
} |
||||||
|
|
||||||
|
/// 带降级的解析流程 |
||||||
|
static Future<Map<String, String>> _parseWithFallback(String path, int maxBytes) async { |
||||||
|
try { |
||||||
|
// 优先尝试快速解析 |
||||||
|
return await _fastParseRootAttributes(path, maxBytes); |
||||||
|
} catch (e) { |
||||||
|
// 快速解析失败时降级到DOM解析 |
||||||
|
return await _domParseRootAttributes(path); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// 快速解析方案(正则匹配) |
||||||
|
static Future<Map<String, String>> _fastParseRootAttributes(String path, int maxBytes) async { |
||||||
|
final file = File(path); |
||||||
|
final raf = await file.open(); |
||||||
|
try { |
||||||
|
// 仅读取文件开头部分 |
||||||
|
final buffer = await raf.read(maxBytes); |
||||||
|
final content = utf8.decode(buffer); |
||||||
|
|
||||||
|
// 使用正则提取开始标签属性 |
||||||
|
final startTag = RegExp( |
||||||
|
r'(?:<\?xml[^?>]*\?>[\s\r\n]*)?<([^\s>]+)([^>]*)>', |
||||||
|
caseSensitive: false, |
||||||
|
).firstMatch(content); |
||||||
|
if (startTag == null) throw Exception('No start tag found'); |
||||||
|
|
||||||
|
final attrs = _parseAttributes(startTag.group(2)!); |
||||||
|
return _extractRequiredAttributes(attrs); |
||||||
|
} finally { |
||||||
|
await raf.close(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// DOM解析降级方案 |
||||||
|
static Future<Map<String, String>> _domParseRootAttributes(String path) async { |
||||||
|
final content = await File(path).readAsString(); |
||||||
|
final document = XmlDocument.parse(content); |
||||||
|
final attrs = document.rootElement.attributes.fold<Map<String, String>>( |
||||||
|
{}, |
||||||
|
(map, attr) => map..[attr.name.qualified] = attr.value, |
||||||
|
); |
||||||
|
return _extractRequiredAttributes(attrs); |
||||||
|
} |
||||||
|
|
||||||
|
/// 辅助方法:解析属性字符串 |
||||||
|
static Map<String, String> _parseAttributes(String attrStr) { |
||||||
|
return RegExp(r'(\w+)="([^"]*)"') |
||||||
|
.allMatches(attrStr) |
||||||
|
.fold<Map<String, String>>({}, (map, match) => map..[match.group(1)!] = match.group(2)!); |
||||||
|
} |
||||||
|
|
||||||
|
/// 辅助方法:提取目标属性 |
||||||
|
static Map<String, String> _extractRequiredAttributes(Map<String, String> attrs) { |
||||||
|
return {'chineseName': attrs['chineseName'] ?? '', 'objectId': attrs['objectId'] ?? ''}; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue