- 概述
- XML基础概念
- 方案一:正则表达式提取
- 方案二:WebView + JavaScript DOM解析
- 方案三:文本分割函数
- 实战案例:RSS订阅解析
- 实战案例:天气API XML解析
- 方案对比
- 常见问题
- 总结
概述
XML(eXtensible Markup Language)是一种常见的数据交换格式,许多Web API仍返回XML格式数据。App Inventor 2没有内置XML解析积木块,但可以通过以下几种方案解析XML数据:
- 正则表达式提取 — 最简单,适合结构简单的XML
- WebView + JavaScript DOM解析 — 最强大,使用浏览器的XML解析能力
- 文本分割函数 — 适合固定格式的XML响应
- 扩展组件 — 社区提供的XML解析扩展
XML基础概念
XML结构示例
<?xml version="1.0" encoding="UTF-8"?>
<weather>
<city id="101010100">
<name>北京</name>
<temp>25</temp>
<humidity>60</humidity>
<forecast>
<day date="2026-05-18">
<high>28</high>
<low>18</low>
<desc>晴转多云</desc>
</day>
<day date="2026-05-19">
<high>26</high>
<low>17</low>
<desc>多云</desc>
</day>
</forecast>
</city>
</weather>
XML核心术语
| 术语 | 说明 | 示例 |
|---|---|---|
| 元素(Element) | XML的基本组成单元 | <name>北京</name> |
| 标签(Tag) | 元素的开始和结束标记 | <name> </name> |
| 属性(Attribute) | 元素的附加信息 | id="101010100" |
| 根元素(Root) | XML的最外层元素 | <weather> |
| 子元素(Child) | 嵌套在元素内的元素 | <temp> 是 <city> 的子元素 |
方案一:正则表达式提取
适用场景
- XML结构简单、层级少
- 只需要提取少量字段
- 快速原型开发
示例:提取天气API返回的温度
当 Web1.收到文本(响应内容)
// 提取 <temp> 标签内容
设 temp = 从文本 响应内容 中提取正则表达式 "<temp>(.*?)</temp>" 的第1个捕获组
// 提取 <name> 标签内容
设 cityName = 从文本 响应内容 中提取正则表达式 "<name>(.*?)</name>" 的第1个捕获组
设 标签_结果.文本 = cityName & "温度:" & temp & "°C"
提取带属性的值
// 提取属性值:date="2026-05-18"
设 dateValue = 从文本 xml文本 中提取正则表达式 'date="([^"]*)"' 的第1个捕获组
// 提取多个同名元素(如多个 <day>)
设 dayList = 从文本 xml文本 中提取正则表达式 "<day.*?>(.*?)</day>" 的所有匹配项
正则表达式常用模式
| 目标 | 正则表达式 | 说明 |
|---|---|---|
| 提取标签内容 | <tag>(.*?)</tag> |
非贪婪匹配 |
| 提取属性值 | attr="([^"]*)" |
匹配引号内内容 |
| 提取所有匹配 | 使用全局匹配 | 文本.提取所有正则匹配() |
方案二:WebView + JavaScript DOM解析
适用场景
- 复杂嵌套XML
- 需要精确解析多层结构
- 需要处理XML属性
- 数据量较大
实现步骤
步骤1:创建HTML解析器文件
创建 xml_parser.html 放到项目Assets中:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="result"></div>
<script>
function parseXML(xmlString) {
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(xmlString, "text/xml");
// 检查解析错误
var errorNode = xmlDoc.querySelector('parsererror');
if (errorNode) {
window.AppInventor.setWebViewString("ERROR:" + errorNode.textContent);
return;
}
return xmlDoc;
}
// 提取单个元素文本
function getElementText(xmlString, tagName) {
var xmlDoc = parseXML(xmlString);
if (!xmlDoc) return;
var elements = xmlDoc.getElementsByTagName(tagName);
if (elements.length > 0) {
window.AppInventor.setWebViewString(elements[0].textContent);
}
}
// 提取所有同名元素,返回JSON数组
function getAllElements(xmlString, tagName) {
var xmlDoc = parseXML(xmlString);
if (!xmlDoc) return;
var elements = xmlDoc.getElementsByTagName(tagName);
var result = [];
for (var i = 0; i < elements.length; i++) {
result.push(elements[i].textContent);
}
window.AppInventor.setWebViewString(JSON.stringify(result));
}
// 提取元素属性
function getAttribute(xmlString, tagName, attrName) {
var xmlDoc = parseXML(xmlString);
if (!xmlDoc) return;
var elements = xmlDoc.getElementsByTagName(tagName);
if (elements.length > 0) {
window.AppInventor.setWebViewString(elements[0].getAttribute(attrName));
}
}
// 提取嵌套结构为JSON
function xmlToJson(xmlString, parentTag) {
var xmlDoc = parseXML(xmlString);
if (!xmlDoc) return;
var parents = xmlDoc.getElementsByTagName(parentTag);
var result = [];
for (var i = 0; i < parents.length; i++) {
var obj = {};
var children = parents[i].children;
for (var j = 0; j < children.length; j++) {
obj[children[j].tagName] = children[j].textContent;
}
// 也获取属性
if (parents[i].attributes) {
for (var k = 0; k < parents[i].attributes.length; k++) {
obj["_" + parents[i].attributes[k].name] = parents[i].attributes[k].value;
}
}
result.push(obj);
}
window.AppInventor.setWebViewString(JSON.stringify(result));
}
</script>
</body>
</html>
步骤2:在App Inventor中使用
当 Screen1.初始化
设 WebView1.主页地址 = "file:///android_asset/xml_parser.html"
// 获取XML并解析
当 Web1.收到文本(响应内容)
// 将XML传给WebView解析
调用 WebView1.运行JavaScript("getElementText('" & 替换特殊字符(响应内容) & "', 'temp')")
// 接收WebView解析结果
当 WebView1.WebView字符串改变(值)
如果 值 以 "ERROR" 开头
标签_结果.文本 = "解析错误"
否则
标签_结果.文本 = "温度:" & 值 & "°C"
步骤3:解析复杂嵌套结构
当 按钮_获取预报.被点击
调用 Web1.执行Get请求("http://api.weather.com/forecast")
当 Web1.收到文本(响应内容)
// 提取所有 <day> 元素为JSON数组
调用 WebView1.运行JavaScript("xmlToJson('" & 替换特殊字符(响应内容) & "', 'day')")
当 WebView1.WebView字符串改变(值)
// 值为JSON数组:[{"_date":"2026-05-18","high":"28","low":"18","desc":"晴转多云"}, ...]
设 forecastList = 调用 文本.从JSON解析(值)
// 遍历显示
设 日期1 = 从字典 forecastList 的第1项 获取 "date"
设 高温1 = 从字典 forecastList 的第1项 获取 "high"
替换特殊字符的辅助函数
XML中可能包含单引号,需要转义后传入JavaScript:
定义 替换特殊字符(文本) 返回 结果
设 结果 = 替换全部 文本 中的 "'" 为 "\\'"
设 结果 = 替换全部 结果 中的 换行符 为 ""
返回 结果
方案三:文本分割函数
适用场景
- XML格式固定且简单
- 不想用WebView
- 只需要提取一两个字段
示例
当 Web1.收到文本(响应内容)
// 用 <temp> 作为分隔符
设 parts = 分割文本 响应内容 以 "<temp>"
如果 列表长度(parts) > 1
设 second = 列表第2项(parts)
设 parts2 = 分割文本 second 以 "</temp>"
设 temp值 = 列表第1项(parts2)
标签_温度.文本 = temp值 & "°C"
实战案例:RSS订阅解析
RSS是一种XML格式的新闻订阅源,解析RSS是XML解析的典型应用。
RSS XML结构
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>MIT App Inventor News</title>
<item>
<title>New Extension Released</title>
<link>https://example.com/news/1</link>
<description>A new extension for barcode scanning</description>
<pubDate>Mon, 18 May 2026 10:00:00 GMT</pubDate>
</item>
<item>
<title>Version 2.70 Update</title>
<link>https://example.com/news/2</link>
<description>Chart component improvements</description>
<pubDate>Sun, 17 May 2026 08:00:00 GMT</pubDate>
</item>
</channel>
</rss>
积木块实现
当 Screen1.初始化
设 WebView1.主页地址 = "file:///android_asset/xml_parser.html"
调用 Web1.执行Get请求("https://example.com/rss.xml")
当 Web1.收到文本(响应内容)
调用 WebView1.运行JavaScript("xmlToJson('" & 替换特殊字符(响应内容) & "', 'item')")
当 WebView1.WebView字符串改变(值)
设 itemList = 调用 文本.从JSON解析(值)
设 显示文本 = ""
设 i = 1
当 i ≤ 列表长度(itemList) 执行
设 item = 列表第i项(itemList)
设 title = 从字典 item 获取 "title"
设 desc = 从字典 item 获取 "description"
设 日期 = 从字典 item 获取 "pubDate"
设 显示文本 = 显示文本 & title & "\n" & desc & "\n" & 日期 & "\n\n"
设 i = i + 1
标签_新闻.文本 = 显示文本
实战案例:天气API XML解析
和风天气API示例
当 按钮_查询天气.被点击
设 apiKey = "your_api_key"
设 cityId = "101010100" ' 北京
设 url = "https://devapi.qweather.com/v7/weather/now?location=" & cityId & "&key=" & apiKey & "&lang=zh"
调用 Web1.执行Get请求(url)
当 Web1.收到文本(响应内容)
// 注意:和风天气新版API返回JSON,这里演示旧版XML解析
// 使用正则提取
设 temp = 从文本 响应内容 中提取正则表达式 '"temp":"([^"]*)"' 的第1个捕获组
设 text = 从文本 响应内容 中提取正则表达式 '"text":"([^"]*)"' 的第1个捕获组
标签_天气.文本 = "当前天气:" & text & ",温度:" & temp & "°C"
方案对比
| 方案 | 复杂度 | 能力 | 适用场景 |
|---|---|---|---|
| 正则表达式 | ⭐ | 中等 | 简单XML、少量字段提取 |
| WebView+JS DOM | ⭐⭐⭐ | 强大 | 复杂嵌套XML、大量数据 |
| 文本分割 | ⭐ | 弱 | 固定格式、快速提取 |
| 扩展组件 | ⭐⭐ | 中等 | 需要专业XML处理 |
常见问题
Q1: 为什么解析XML时出现乱码?
确保Web组件的请求头设置了正确的编码:
调用 Web1.设置请求头("Accept-Charset", "UTF-8")
如果API返回的是GBK编码,需要先转码或在WebView中指定编码。
Q2: 正则表达式提取不到内容怎么办?
常见原因:
- XML中有命名空间前缀(如
<ws:temp>),需要在正则中包含 - 标签跨行,
.默认不匹配换行符 - 大小写不匹配
Q3: WebView解析报parsererror?
XML格式不规范(未闭合标签、特殊字符未转义等)。在JavaScript中先检查错误:
var errorNode = xmlDoc.querySelector('parsererror');
if (errorNode) {
window.AppInventor.setWebViewString("ERROR");
return;
}
Q4: 如何处理大型XML文件?
对于大XML(>1MB):
- 使用WebView方案(浏览器DOM解析效率高)
- 避免在App Inventor变量中保存完整XML文本
- 分段解析,只提取需要的部分
Q5: 有没有XML解析扩展?
MIT App Inventor官方没有提供XML解析扩展,但社区中有一些第三方扩展:
- 在 AppyBuilder 或 Kodular 社区搜索 “XML Parser Extension”
- Niotron IDE 提供了内置的 XML 解析组件
总结
App Inventor 2虽然没有内置XML解析组件,但通过正则表达式、WebView+JavaScript、文本分割等方案完全可以处理常见的XML数据。推荐方案:
- 简单提取 → 正则表达式
- 复杂解析 → WebView + JavaScript DOMParser
- 固定格式 → 文本分割函数
对于新项目,建议优先选择返回JSON格式的API,因为App Inventor 2内置了完善的字典/JSON支持。
版权声明:MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权,本文档由 ai2claw 🐝 整理。
扫码添加客服咨询