programing

'Element'를 통해 Python에서 네임스페이스가 있는 XML 구문 분석나무'

bestprogram 2023. 7. 1. 09:07

'Element'를 통해 Python에서 네임스페이스가 있는 XML 구문 분석나무'

파이썬을 사용하여 구문 분석하고 싶은 다음 XML이 있습니다.ElementTree:

<rdf:RDF xml:base="http://dbpedia.org/ontology/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns="http://dbpedia.org/ontology/">

    <owl:Class rdf:about="http://dbpedia.org/ontology/BasketballLeague">
        <rdfs:label xml:lang="en">basketball league</rdfs:label>
        <rdfs:comment xml:lang="en">
          a group of sports teams that compete against each other
          in Basketball
        </rdfs:comment>
    </owl:Class>

</rdf:RDF>

모두 찾고 싶습니다.owl:Class태그를 지정한 다음 모두의 값을 추출합니다.rdfs:label그들 내부의 예들.다음 코드를 사용하고 있습니다.

tree = ET.parse("filename")
root = tree.getroot()
root.findall('owl:Class')

네임스페이스 때문에 다음과 같은 오류가 발생합니다.

SyntaxError: prefix 'owl' not found in prefix map

http://effbot.org/zone/element-namespaces.htm 에서 문서를 읽으려고 했지만 위의 XML에 여러 개의 중첩된 이름 공간이 있기 때문에 여전히 이 작업을 수행할 수 없습니다.

모든 것을 찾기 위해 코드를 변경하는 방법을 알려주세요.owl:Class꼬리표

당신은 그것을 줄 필요가 있습니다..find(),findall()그리고.iterfind()메서드: 명시적 네임스페이스 사전:

namespaces = {'owl': 'http://www.w3.org/2002/07/owl#'} # add more as needed

root.findall('owl:Class', namespaces)

접두사는 에서만 검색됩니다.namespaces매개 변수를 입력합니다.즉, 원하는 네임스페이스 접두사를 사용할 수 있습니다. API는 다음과 같이 분리됩니다.owl:part, 에서 해당 네임스페이스 URL을 검색합니다.namespaces사전을 선택한 다음 검색을 변경하여 XPath 식을 찾습니다.{http://www.w3.org/2002/07/owl}Class대신.물론 동일한 구문을 사용할 수도 있습니다.

root.findall('{http://www.w3.org/2002/07/owl#}Class')

요소의 네임스페이스사용한 XML 구문 분석 섹션도 참조하십시오.트리 문서.

라이브러리로 전환할 수 있으면 라이브러리가 동일한 요소를 지원하는 것이 더 좋습니다.트리 API, 그러나 사용자에 대한 네임스페이스를 수집합니다..nsmap요소에 대한 속성이며 일반적으로 우수한 네임스페이스 지원을 제공합니다.

다음은 네임스페이스를 하드 코딩하거나 텍스트를 스캔하지 않고 lxml로 이 작업을 수행하는 방법입니다(Martjn Pieters가 언급한 바와 같이).

from lxml import etree
tree = etree.parse("filename")
root = tree.getroot()
root.findall('owl:Class', root.nsmap)

업데이트:

5년이 지난 지금도 저는 이 문제의 다양성에 직면해 있습니다.위에서 보여드린 것처럼 lxml이 도움이 되지만 모든 경우에 도움이 되는 것은 아닙니다.의견제출자들은 문서 병합에 관한 이 기법에 대해 타당한 지적을 할 수 있지만, 대부분의 사람들이 단순히 문서를 검색하는 데 어려움을 겪고 있다고 생각합니다.

다음은 제가 처리한 또 다른 사례입니다.

<?xml version="1.0" ?><Tag1 xmlns="http://www.mynamespace.com/prefix">
<Tag2>content</Tag2></Tag1>

접두사가 없는 xmlns는 접두사가 없는 태그가 이 기본 네임스페이스를 수신함을 의미합니다.즉, 태그2를 검색할 때 네임스페이스를 포함해야 태그2를 찾을 수 있습니다.하지만 lxml은 없음을 키로 하는 nsmap 항목을 생성하여 검색할 방법을 찾지 못했습니다.그래서 이렇게 새로운 네임스페이스 사전을 만들었습니다.

namespaces = {}
# response uses a default namespace, and tags don't mention it
# create a new ns map using an identifier of our choice
for k,v in root.nsmap.iteritems():
    if not k:
        namespaces['myprefix'] = v
e = root.find('myprefix:Tag2', namespaces)

메모Python's Element에 유용한 답변입니다.하드 코딩된 네임스페이스를 사용하지 않는 트리 표준 라이브러리.

하려면 XML 데이를네스의이접두및 URI데사용있다를 사용할 수 .ElementTree.iterparse함수, 네임스페이스 시작 이벤트만 구문 분석(start-ns):

>>> from io import StringIO
>>> from xml.etree import ElementTree
>>> my_schema = u'''<rdf:RDF xml:base="http://dbpedia.org/ontology/"
...     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
...     xmlns:owl="http://www.w3.org/2002/07/owl#"
...     xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
...     xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
...     xmlns="http://dbpedia.org/ontology/">
... 
...     <owl:Class rdf:about="http://dbpedia.org/ontology/BasketballLeague">
...         <rdfs:label xml:lang="en">basketball league</rdfs:label>
...         <rdfs:comment xml:lang="en">
...           a group of sports teams that compete against each other
...           in Basketball
...         </rdfs:comment>
...     </owl:Class>
... 
... </rdf:RDF>'''
>>> my_namespaces = dict([
...     node for _, node in ElementTree.iterparse(
...         StringIO(my_schema), events=['start-ns']
...     )
... ])
>>> from pprint import pprint
>>> pprint(my_namespaces)
{'': 'http://dbpedia.org/ontology/',
 'owl': 'http://www.w3.org/2002/07/owl#',
 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
 'rdfs': 'http://www.w3.org/2000/01/rdf-schema#',
 'xsd': 'http://www.w3.org/2001/XMLSchema#'}

그런 다음 사전을 인수로 검색 기능에 전달할 수 있습니다.

root.findall('owl:Class', my_namespaces)

저는 이와 유사한 코드를 사용해왔고 문서를 항상 읽을 가치가 있다는 것을 알게 되었습니다.여느 때처럼!

find all ()는 현재 태그의 직접 자식 요소만 찾습니다.전부는 아닙니다.

특히 크고 복잡한 xml 파일을 처리하여 하위 요소(예: 하위 요소)도 포함되도록 하는 경우에는 코드를 다음과 같이 사용해 보는 것이 좋습니다.만약 당신이 당신의 xml에서 요소들이 어디에 있는지 알고 있다면, 나는 그것이 괜찮을 것이라고 생각합니다!기억할 만한 가치가 있다고 생각했어요

root.iter()

ref: https://docs.python.org/3/library/xml.etree.elementtree.html#finding-interesting-elements "Element.findall()은 현재 요소의 직접 자식인 태그가 있는 요소만 찾습니다.Element.find()는 특정 태그가 있는 첫 번째 자식을 찾고 Element.text는 요소의 텍스트 내용에 액세스합니다.Element.get()은 요소의 속성에 액세스합니다."

네임스페이스 형식으로 네임스페이스를 가져오려면 다음과 같이 하십시오.{myNameSpace}다음을 수행할 수 있습니다.

root = tree.getroot()
ns = re.match(r'{.*}', root.tag).group(0)

이러한 방식으로 나중에 코드에서 문자열 보간(Python 3) 등을 사용하여 노드를 찾을 수 있습니다.

link = root.find(f"{ns}link")

이것은 기본적으로 David Brunato의 대답이지만, 저는 그의 대답이 적어도 제 파이썬 3.6 설치에서 기본 네임스페이스인 빈 문자열에 심각한 문제가 있다는 것을 발견했습니다.그의 코드에서 추출한 기능은 다음과 같습니다.

from io import StringIO
from xml.etree import ElementTree
def get_namespaces(xml_string):
    namespaces = dict([
            node for _, node in ElementTree.iterparse(
                StringIO(xml_string), events=['start-ns']
            )
    ])
    namespaces["ns0"] = namespaces[""]
    return namespaces

ns0빈 네임스페이스에 대한 자리 표시자일 뿐이며 원하는 임의의 문자열로 바꿀 수 있습니다.

내가 하면 됩니다.

my_namespaces = get_namespaces(my_schema)
root.findall('ns0:SomeTagWithDefaultNamespace', my_namespaces)

또한 기본 네임스페이스를 사용하는 태그에 대한 정답도 생성합니다.

제 해결책은 @Martijn Pieters의 논평에 기초하고 있습니다.

register_namespace직렬화에만 영향을 미치며 검색에는 영향을 주지 않습니다.

그래서 여기서 요령은 직렬화와 검색을 위해 다른 사전을 사용하는 것입니다.

namespaces = {
    '': 'http://www.example.com/default-schema',
    'spec': 'http://www.example.com/specialized-schema',
}

이제 구문 분석 및 쓰기를 위해 모든 네임스페이스를 등록합니다.

for name, value in namespaces.iteritems():
    ET.register_namespace(name, value)

을 위해 색용검(find(),findall(),iterfind()비어 있지 않은 접두사가 필요합니다.이러한 함수에 수정된 사전을 전달합니다(여기서는 원래 사전을 수정하지만 이름 공간이 등록된 후에만 수정해야 합니다).

self.namespaces['default'] = self.namespaces['']

그럼 이제 제은, .find()는 패리를사수있다니습과 할 수 .default접두사:

print root.find('default:myelem', namespaces)

그렇지만

tree.write(destination)

에서는 기본 네임스페이스의 요소에 접두사를 사용하지 않습니다.

언급URL : https://stackoverflow.com/questions/14853243/parsing-xml-with-namespace-in-python-via-elementtree