【问题标题】:Searching for xpath expression with colon in attribute name throws exception (node.js elementtree module)在属性名称中搜索带有冒号的 xpath 表达式会引发异常(node.js elementtree 模块)
【发布时间】:2012-06-23 02:53:28
【问题描述】:

使用 nodejs 中的 elementtree 包,我正在尝试验证 xml 文件(特别是 android 清单文件)中是否存在某个 xml 属性。

var manifestTxt = fs.readFileSync('AndroidManifest.xml', 'utf-8'),
    manifestDoc = new et.ElementTree(et.XML(manifestTxt)),
    expected = 'application/activity[@android:name="com.whatever.app"]';

test.ok(manifestDoc.find(expected));

我收到以下异常:

node_modules/elementtree/lib/elementpath.js:210
      throw new SyntaxError(token, 'Invalid attribute predicate');
        ^
Error: Invalid attribute predicate

它似乎不喜欢属性名称中的冒号,但没有它,搜索不匹配。我认为我处理命名空间错误 - 但找不到正确的方法。

编辑这是我正在搜索的示例 xml:

<?xml version='1.0' encoding='utf-8'?>
<manifest ... xmlns:android="http://schemas.android.com/apk/res/android">
    <application android:debuggable="true" android:icon="@drawable/icon" android:label="@string/app_name">&#xA; 
        <activity android:label="@string/app_name" android:name="com.whatever.app">&#xA;                
            <intent-filter>&#xA;</intent-filter>
        </activity> 
    </application>
    <uses-sdk android:minSdkVersion="5" />
</manifest>

【问题讨论】:

  • 你试过转义冒号\:吗?

标签: javascript node.js xpath elementtree


【解决方案1】:

Elementtree 需要命名空间 URI,而不是命名空间前缀。

var manifestTxt = fs.readFileSync('AndroidManifest.xml', 'utf-8'),
    manifestDoc = new et.ElementTree(et.XML(manifestTxt)),
    expected = '//application/activity[@{http://schemas.android.com/apk/res/android}name="com.whatever.app"]';

test.ok( manifestDoc.find(expected) );

见:ElementTree: Working with Qualified Names


编辑node-elementtree 的 XPath 实现似乎根本不支持命名空间currently

想念你必须做一些跑腿工作:

var manifestTxt = fs.readFileSync('AndroidManifest.xml', 'utf-8'),
    manifestDoc = new et.ElementTree(et.XML(manifestTxt)),
    activities = manifestDoc.findall('//application/activity'), i;

for (i=0; i<activities.length; i++) {
  if ( activities[i].attrib['android:name'] === 'com.whatever.app' ) {
    test.ok(true);
  }
}

if ( activities[i].attrib['android:name'] === 'com.whatever.app' ) { 这行主要是猜测。

我不知道解析器如何处理命名空间属性。如有疑问,只需将整个 activities[i].attrib 转储到控制台,然后查看解析器做了什么。相应地调整上面的代码。恐怕这与您在有限的 XPath 支持下所获得的一样接近。

【讨论】:

  • 谢谢,我确实尝试过,虽然它不再抛出异常,但查找失败(所以我认为它也是错误的)。我添加了我正在搜索的示例 xml。那么问题就变成了,为什么查找失败?
  • @DimitreNovaatchev 没错。无论如何,这就是 ElementTree 根据文档的工作方式(请参阅上面的“使用限定名称”链接)。我对此无能为力。
  • @wildabeast 看着the source,我没有看到任何迹象表明 node-elementtree 甚至 具有 命名空间支持。 XPath 实现非常基础。也没有功能支持。您能确认这是您使用的版本吗?
  • 那是我正在使用的版本,是的。所以你可能对缺乏命名空间支持是正确的。谢谢。
【解决方案2】:

如果您不知道如何注册命名空间并为其使用相关前缀,请使用

application/activity
   [@*[local-name()=name' 
     and 
      namespace-uri() = 'http://schemas.android.com/apk/res/android'
      ] 
   = 
    'com.whatever.app'
   ]

更简单的表达式在一般情况下不安全,但在这种特定情况下可能会选择想要的节点

application/activity[@*[local-name()='name'] = 'com.whatever.app']

或者这个表达方式

application/activity[@*[name()='android:name'] = 'com.whatever.app']

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-20
    • 2012-06-09
    • 2015-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-29
    相关资源
    最近更新 更多