XPath选择当前节点的属性?

4
我使用Python和lxml来处理XML。在查询/筛选以获取我想要的节点后,我遇到了一些问题。如何通过xpath获取其属性值?这是我的输入示例。
>print(etree.tostring(node, pretty_print=True ))
<rdf:li xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"  rdf:resource="urn:miriam:obo.chebi:CHEBI%3A37671"/>

我想要的值在resource=...中。目前我只是使用lxml来获取该值。我想知道是否有可能仅使用纯xpath来实现?谢谢。
编辑:忘了说,这不是根节点,所以我不能在这里使用//。我的xml文件中有大约2000-3000个其他节点。我的第一次尝试是尝试使用".@attrib"和"self::*@",但这些似乎不起作用。
编辑2:我会尽力解释(好吧,这是我第一次使用xpath解决xml问题,并且英语不是我最喜欢的领域...)。这是我的输入片段http://pastebin.com/kZmVdbQQ(从这里http://www.comp-sys-bio.org/yeastnet/使用版本4获取完整信息)。
在我的代码中,我尝试使用资源链接chebi(<rdf:li rdf:resource="urn:miriam:obo.chebi:...."/>)获取speciesTypes节点。然后,我尝试从rdf:li的rdf:resource属性中获取值。问题是,我相当确定如果我从父节点(如speciesTypes)开始,很容易就能获取子节点中的属性,但是如果我从rdf:li开始,我不知道该怎么做。据我所知,在xpath中的“//”将会查找所有节点而不仅仅是当前节点。
以下是我的代码:
import lxml.etree as etree

tree = etree.parse("yeast_4.02.xml")
root = tree.getroot()
ns = {"sbml": "http://www.sbml.org/sbml/level2/version4", 
      "rdf":"http://www.w3.org/1999/02/22-rdf-syntax-ns#",
      "body":"http://www.w3.org/1999/xhtml",
      "re": "http://exslt.org/regular-expressions"
      }
#good enough for now
maybemeta = root.xpath("//sbml:speciesType[descendant::rdf:li[starts-with(@rdf:resource, 'urn:miriam:obo.chebi') and not(starts-with(@rdf:resource, 'urn:miriam:uniprot'))]]", namespaces = ns)

def extract_name_and_chebi(node):
    name = node.attrib['name']
    chebies = node.xpath("./sbml:annotation//rdf:li[starts-with(@rdf:resource, 'urn:miriam:obo.chebi') and not(starts-with(@rdf:resource, 'urn:miriam:uniprot'))]", namespaces=ns) #get all rdf:li node with chebi resource
    assert len(chebies) == 1
    #my current solution to get rdf:resource value from rdf:li node
    rdfNS = "{" + ns.get('rdf') + "}"
    chebi = chebies[0].attrib[rdfNS + 'resource'] 
    #do protein later
    return (name, chebi)

    metaWithChebi = map(extract_name_and_chebi, maybemeta)
fo = open("metabolites.txt", "w")

for name, chebi in metaWithChebi:
    fo.write("{0}\t{1}\n".format(name, chebi))

使用XPath解析RDF XML并不是一个好主意。XML是一棵树,但RDF是一个图形,你可以用不同的RDFXML表示相同的RDF图形。你应该将XML视为一个交换格式,并使用RDF库从XML创建图形,然后直接使用图形进行操作。 - Francis Avila
谢谢您的建议。但在这项工作中,我只想提取带有一些信息的节点,然后对其进行一些格式化,以便在电子表格中使用。 - Tg.
3个回答

3

在XPath查询中,使用@前缀来指定属性名称:

>>> from lxml import etree
>>> xml = """\
... <?xml version="1.0" encoding="utf8"?>
... <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
...     <rdf:li rdf:resource="urn:miriam:obo.chebi:CHEBI%3A37671"/>
... </rdf:RDF>
... """
>>> tree = etree.fromstring(xml)
>>> ns = {'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'}
>>> tree.xpath('//rdf:li/@rdf:resource', namespaces=ns)
['urn:miriam:obo.chebi:CHEBI%3A37671']

编辑

以下是问题中脚本的修订版本:

import lxml.etree as etree

ns = {
    'sbml': 'http://www.sbml.org/sbml/level2/version4',
    'rdf':'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
    'body':'http://www.w3.org/1999/xhtml',
    're': 'http://exslt.org/regular-expressions',
    }

def extract_name_and_chebi(node):
    chebies = node.xpath("""
        .//rdf:li[
        starts-with(@rdf:resource, 'urn:miriam:obo.chebi')
        ]/@rdf:resource
        """, namespaces=ns)
    return node.attrib['name'], chebies[0]

with open('yeast_4.02.xml') as xml:
    tree = etree.parse(xml)

    maybemeta = tree.xpath("""
        //sbml:speciesType[descendant::rdf:li[
        starts-with(@rdf:resource, 'urn:miriam:obo.chebi')]]
        """, namespaces = ns)

    with open('metabolites.txt', 'w') as output:
        for node in maybemeta:
            output.write('%s\t%s\n' % extract_name_and_chebi(node))

忘了说,这不是根节点,所以我认为“//”在这里不起作用。 - Tg.
@Tg,我不理解你的评论或者你在问题中添加的编辑。你的XML文件结构是什么样子的?你目前使用的代码是用来解析和查询它的吗?如果你发布一个像我回答中的小型工作示例脚本,那么人们提供更有用的答案会更容易些。 - ekhumoro
@Tg。我已经更新了我的答案,使用你问题中的修订版本脚本。它会产生完全相同的输出。 - ekhumoro

1

要选择当前节点的名为rdf:resource的属性,请使用以下XPath表达式:

@rdf:resource

为了使其“正常工作”,您必须注册前缀“rdf:”与相应命名空间的关联。 如果您不知道如何注册rdf命名空间,仍然可以使用此XPath表达式选择属性:
@*[name()='rdf:resource']

0

好的,我明白了。我在这里需要的xpath表达式是"./@rdf:resource"而不是".@rdf:resource"。但是为什么呢?我以为"./"表示当前节点的子节点。


属性也是子节点! - mucaho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接