You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用NodeJS根据Text属性获取元素的完整XPath

如何使用NodeJS获取通过Text属性定位的元素的完整XPath?

以下是对应的XML内容:

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<hierarchy index="0" class="hierarchy" rotation="0" width="1440" height="3036">
  <android.widget.FrameLayout index="0" package="com.google.android.permissioncontroller" class="android.widget.FrameLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[37,1017][1403,2102]" displayed="true">
    <android.widget.FrameLayout index="0" package="com.google.android.permissioncontroller" class="android.widget.FrameLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[37,1017][1403,2102]" displayed="true">
      <android.widget.FrameLayout index="0" package="com.google.android.permissioncontroller" class="android.widget.FrameLayout" text="" resource-id="android:id/content" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[37,1017][1403,2102]" displayed="true">
        <android.widget.ScrollView index="0" package="com.google.android.permissioncontroller" class="android.widget.ScrollView" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[37,1017][1403,2102]" displayed="true">
          <android.widget.LinearLayout index="0" package="com.google.android.permissioncontroller" class="android.widget.LinearLayout" text="" resource-id="com.android.permissioncontroller:id/grant_singleton" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[37,1017][1403,2102]" displayed="true">
            <android.widget.LinearLayout index="0" package="com.google.android.permissioncontroller" class="android.widget.LinearLayout" text="" resource-id="com.android.permissioncontroller:id/grant_dialog" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[37,1017][1403,2102]" displayed="true">
              <android.widget.LinearLayout index="0" package="com.google.android.permissioncontroller" class="android.widget.LinearLayout" text="" resource-id="com.android.permissioncontroller:id/content_container" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[93,1073][1347,1549]" displayed="true">
                <android.widget.LinearLayout index="0" package="com.google.android.permissioncontroller" class="android.widget.LinearLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[177,1136][1263,1465]" displayed="true">
                  <android.widget.ImageView index="0" package="com.google.android.permissioncontroller" class="android.widget.ImageView" text="" resource-id="com.android.permissioncontroller:id/permission_icon" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[664,1136][776,1248]" displayed="true" />
                  <android.widget.TextView index="1" package="com.google.android.permissioncontroller" class="android.widget.TextView" text="Allow App to send you notifications?" resource-id="com.android.permissioncontroller:id/permission_message" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[177,1290][1263,1465]" displayed="true" />
                </android.widget.LinearLayout>
              </android.widget.LinearLayout>
              <android.widget.LinearLayout index="1" package="com.google.android.permissioncontroller" class="android.widget.LinearLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[93,1549][1347,2046]" displayed="true">
                <android.widget.Button index="0" package="com.google.android.permissioncontroller" class="android.widget.Button" text="Allow" resource-id="com.android.permissioncontroller:id/permission_allow_button" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[177,1556][1263,1752]" displayed="true" />
                <android.widget.Button index="1" package="com.google.android.permissioncontroller" class="android.widget.Button" text="Don’t allow" resource-id="com.android.permissioncontroller:id/permission_deny_button" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[177,1766][1263,1962]" displayed="true" />
              </android.widget.LinearLayout>
            </android.widget.LinearLayout>
          </android.widget.LinearLayout>
        </android.widget.ScrollView>
      </android.widget.FrameLayout>
    </android.widget.FrameLayout>
  </android.widget.FrameLayout>
</hierarchy>

我需要获取文本为Allow的第一个按钮的完整XPath,预期XPath为:
/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.ScrollView/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.LinearLayout[2]/android.widget.Button[1]


实现方案

可以用NodeJS的xmldom和xpath库解析XML并生成目标XPath,步骤如下:

  1. 安装依赖
    执行命令安装所需库:
npm install xmldom xpath
  1. 编写代码
    以下代码会定位到文本为Allow的按钮,并生成完整层级XPath:
const { DOMParser } = require('xmldom');
const xpath = require('xpath');

// 替换为你的XML内容
const xmlContent = `<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<hierarchy index="0" class="hierarchy" rotation="0" width="1440" height="3036">
  <!-- 完整XML内容 -->
</hierarchy>`;

// 解析XML为DOM对象
const doc = new DOMParser().parseFromString(xmlContent, 'text/xml');
const select = xpath.useNamespaces({});

// 定位目标元素
const targetElement = select("//*[@text='Allow']", doc)[0];

// 生成完整XPath的函数
function generateFullXPath(element) {
    const path = [];
    let current = element;
    while (current && current.nodeType === 1) {
        let tagName = current.tagName;
        // 统计同级同标签元素数量,确定索引
        const siblings = current.parentNode.childNodes;
        let sameTagCount = 0;
        let position = 1;
        for (const sibling of siblings) {
            if (sibling.nodeType === 1 && sibling.tagName === tagName) {
                sameTagCount++;
                if (sibling === current) position = sameTagCount;
            }
        }
        // 同级同标签超过1个时添加索引
        if (sameTagCount > 1) tagName += `[${position}]`;
        path.unshift(tagName);
        current = current.parentNode;
    }
    return '/' + path.join('/');
}

// 输出结果
const fullXPath = generateFullXPath(targetElement);
console.log(fullXPath);
  1. 代码说明
  • 用DOMParser把XML字符串转为DOM对象;
  • 用XPath表达式//*[@text='Allow']定位目标按钮;
  • generateFullXPath函数从目标元素向上遍历父节点,统计每个节点在同级同标签中的位置,拼接成完整层级XPath;
  • 运行代码后输出的XPath与预期完全一致。

内容的提问来源于stack exchange,提问作者Aritra Nayak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 04:25:19