Найти - Пользователи
Полная версия: Проблема с парсингом xml файла
Начало » Python для новичков » Проблема с парсингом xml файла
1
Agiza
Добрый день! Начать парсить файлы, указанные в примерах для начинающих (довольно простые), у меня получается. Но xml файл посложнее начать парсить не могу. Вот часть кода xml файла:
<?xml version="1.0" encoding="UTF-8"?><export xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://zakupki.gov.ru/oos/export/1" xmlns:oos="http://zakupki.gov.ru/oos/types/1">
  <contract schemeVersion="1.0">
    <oos:id>13700110</oos:id>
    <oos:regNum>0365200021414000003</oos:regNum>
    <oos:number>1</oos:number>
    <oos:publishDate>2014-01-13T17:18:41Z</oos:publishDate>
    <oos:signDate>2014-01-09</oos:signDate>
    <oos:versionNumber>0</oos:versionNumber>
    <oos:foundation>
      <oos:oosOrder>
        <oos:notificationNumber>0365200021413000103</oos:notificationNumber>
        <oos:lotNumber>1</oos:lotNumber>
        <oos:placing>9</oos:placing>
      </oos:oosOrder>
    </oos:foundation>
    <oos:customer>
      <oos:regNum>03652000214</oos:regNum>
      <oos:fullName>областное государственное бюджетное учреждение &quot;Служба хозяйственного обеспечения&quot;</oos:fullName>
      <oos:inn>7017297271</oos:inn>
      <oos:kpp>701701001</oos:kpp>
    </oos:customer>
    <oos:protocolDate>2013-12-25</oos:protocolDate>
    <oos:documentBase>Протокол рассмотрения и оценки котировочных заявок №0365200021413000103-П от 25.12.2013; Протокол рассмотрения и оценки котировочных заявок №0365200021413000103-П от 25.12.2013</oos:documentBase>
    <oos:price>230400</oos:price>
  </contract>
</export>

Вот код, который я пишу, пытаясь спарсить файл:
from xml.etree import ElementTree
fname='contract.xml'
dom=ElementTree.parse(fname)
name = dom.findall('contract/oos:id')
print (name)

Выдаёт ошибку:
Traceback (most recent call last):
File “C:\Program Files (x86)\Python\lib\xml\etree\ElementPath.py”, line 257, in iterfind
selector = _cache
KeyError: ('contract/oos:id', None)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “C:\Program Files (x86)\Python\lib\xml\etree\ElementPath.py”, line 80, in xpath_tokenizer
raise KeyError
KeyError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “CUsers/Н/Desktop/parser1.py”, line 4, in <module>
name = dom.findall('contract/oos:id')
File “C:\Program Files (x86)\Python\lib\xml\etree\ElementTree.py”, line 697, in findall
return self._root.findall(path, namespaces)
File “C:\Program Files (x86)\Python\lib\xml\etree\ElementPath.py”, line 298, in findall
return list(iterfind(elem, path, namespaces))
File “C:\Program Files (x86)\Python\lib\xml\etree\ElementPath.py”, line 274, in iterfind
token = next()
File “C:\Program Files (x86)\Python\lib\xml\etree\ElementPath.py”, line 83, in xpath_tokenizer
raise SyntaxError(“prefix %r not found in prefix map” % prefix)
File “<string>”, line None
SyntaxError: prefix ‘oos’ not found in prefix map

Убирала “oos:”, тогда программа просто ничего не находит

Я упёрлась в стенку, помогите пожалуйста
doza_and
1: oss это http://zakupki.gov.ru/oos/types/1

:)
Не парьтесь
выполните команду xml2yamlx.py dev.xml dev.yaml
Содержимое xml2yamlx.py:
#!/usr/bin/env python
import yaml
from lxml import etree
import sys
import codecs
import re
#
# Convert an XML document (file) to YAML and write it to stdout.
#
def convertXml2Yaml(inFileName,outFileName):
    doc = etree.parse(inFileName)
    root = doc.getroot()
    if root.nsmap:
        res={}
        res["nsmap"]=root.nsmap
    # Convert the DOM tree into "YAML-able" data structures.
        nsi= dict([(v,k) for k,v in root.nsmap.iteritems()])
        res["root"]=convertXml2YamlAux(root,nsi)
    else:
        res=convertXml2YamlAux(root,{})
    # Ask YAML to dump the data structures to a string.
    with codecs.open(outFileName,"w",encoding="utf-8") as f:
        yaml.safe_dump(res,f,allow_unicode=True)
def reduce_name(name,nsi):
    fnd=re.match(ur"{([^}]+?)}(.+)",name)
    if fnd:
        if fnd.group(1) in nsi:
            return "{k}:{v}".format(k=nsi[fnd.group(1)],v=fnd.group(2))
        else:
            return "{k}:{v}".format(k=fnd.group(1),v=fnd.group(2))
    return name
u"""elements: [name(tag), attr, text,children]"""
def convertXml2YamlAux(obj,nsi):
    # Add the element name.
    nm=reduce_name(obj.tag,nsi)
    text=obj.text
    if text:
        text=text.strip()
    else:
        text=""
    attr=dict([(reduce_name(k,nsi),v) for k,v in obj.attrib.iteritems()])
    if text:
        attr["t"]=text
    childr = [convertXml2YamlAux(i,nsi) for i in obj.iterchildren()]
    res=[nm]
    if attr:
        res.append(attr) # attr is mapping
    if childr:
        res.append(childr) # children is list
    return res
def convertXml2YamlAux(obj,nsi):
    # Add the element name.
    nm=reduce_name(obj.tag,nsi)
    text=obj.text
    if text:
        text=text.strip()
    else:
        text=""
    attr=dict([(reduce_name(k,nsi),v) for k,v in obj.attrib.iteritems()])
    if text:
        attr["t"]=text
    childr = [convertXml2YamlAux(i,nsi) for i in obj.iterchildren()]
    res=[nm]
    if attr:
        res.append(attr) # attr is mapping
    if childr:
        res.append(childr) # children is list
    return res
def main():
    convertXml2Yaml(sys.argv[1],sys.argv[2])
if __name__ == '__main__':
    main()

В результате получите нормальный yaml

nsmap: {null: 'http://zakupki.gov.ru/oos/export/1', oos: 'http://zakupki.gov.ru/oos/types/1',
  xsi: 'http://www.w3.org/2001/XMLSchema-instance'}
root:
- None:export
- - - None:contract
    - {schemeVersion: '1.0'}
    - - - oos:id
        - {t: '13700110'}
      - - oos:regNum
        - {t: '0365200021414000003'}
      - - oos:number
        - {t: '1'}
      - - oos:publishDate
        - {t: '2014-01-13T17:18:41Z'}
      - - oos:signDate
        - {t: '2014-01-09'}
      - - oos:versionNumber
        - {t: '0'}
      - - oos:foundation
        - - - oos:oosOrder
            - - - oos:notificationNumber
                - {t: '0365200021413000103'}
              - - oos:lotNumber
                - {t: '1'}
              - - oos:placing
                - {t: '9'}
      - - oos:customer
        - - - oos:regNum
            - {t: '03652000214'}
          - - oos:fullName
            - {t: областное государственное бюджетное учреждение "Служба хозяйственного
                обеспечения"}
          - - oos:inn
            - {t: '7017297271'}
          - - oos:kpp
            - {t: '701701001'}
      - - oos:protocolDate
        - {t: '2013-12-25'}
      - - oos:documentBase
        - {t: Протокол рассмотрения и оценки котировочных заявок 0365200021413000103-П
            от 25.12.2013; Протокол рассмотрения и оценки котировочных заявок 0365200021413000103-П
            от 25.12.2013}
      - - oos:price
        - {t: '230400'}

И забудьте про xml как про страшный сон.
После несложного упрощения получим:
schemeVersion : '1.0'
id : '13700110'
regNum : '0365200021414000003'
number : '1'
publishDate : '2014-01-13T17:18:41Z'
signDate : '2014-01-09'
versionNumber : '0'
foundation :
    Order :
        notificationNumber : '0365200021413000103'
        lotNumber : '1'
        placing : '9'
customer :
    regNum : '03652000214'
    fullName : областное государственное бюджетное учреждение "Служба хозяйственного обеспечения"
    inn : '7017297271'
    kpp : '701701001'
protocolDate : '2013-12-25'
documentBase : Протокол рассмотрения и оценки котировочных заявок 0365200021413000103-П от 25.12.2013; Протокол рассмотрения и оценки котировочных заявок 0365200021413000103-П от 25.12.2013
price : '230400'

что лучше на мой взгляд читается и проще обрабатывается в python
Agiza
doza_and
1: oss это http://zakupki.gov.ru/oos/types/1:)Не парьтесьвыполните команду xml2yamlx.py dev.xml dev.yamlСодержимое xml2yamlx.py:
Спасибо за подсказку, но в интернете не нашла ничего толкового про парсинг YAML с помощью Python
Поделитесь пожалуйста примерами парсинга или ссылками на примеры.
И ещё вопрос: чем плох такой XML ?)
doza_and
Agiza
И ещё вопрос: чем плох такой XML ?)
Он плох тем что:
1 Неудобен для чтения людьми (особенно небольших файлов).
2 Неоднозначен при загрузке в программы (можно в тексте или в атрибутах данные передавать).
3 Нет прямого соответствия программным структурам данных для основных языков программирования
4 Не поддерживаются нормальные типы данных (обратите внимание что числа у вас на самом деле строки я уж не говорю о дате и времени)
5 Значительно больше по объему (у вас например в 2 раза больше) что важно для интернет приложений.
6 Не поддерживает ссылки (т.е. xml это дерево а yaml может описывать произвольный граф).
7 Не поддерживает потоковую передачу данных (xml надо обязательно прочитать полностью а yaml поддерживает потоки документов). Это очень важно для больших объемов данных.

Загрузить можно при помощи pyyaml
http://pyyaml.org/
http://pyyaml.org/wiki/PyYAMLDocumentation
import codecs
import yaml
data=yaml.load(codecs.open("dev1.yaml","r",encoding="utf-8"))
>>> print(data["id"])
13700110

Конкретно ваш xml плох тем что его неудобно читать и писать программно. И человеку тоже неудобно его читать поскольку слишком много символов разметки структуры.
py.user.next
Agiza
Вот код, который я пишу, пытаясь спарсить файл:
>>> import xml.etree.ElementTree as ET
>>> 
>>> s = """<?xml version="1.0" encoding="UTF-8"?>
... <export xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://zakupki.gov.ru/oos/export/1" xmlns:oos="http://zakupki.gov.ru/oos/types/1">
...   <contract schemeVersion="1.0">
...     <oos:id>13700110</oos:id>
...     <oos:regNum>0365200021414000003</oos:regNum>
...     <oos:number>1</oos:number>
...     <oos:publishDate>2014-01-13T17:18:41Z</oos:publishDate>
...     <oos:signDate>2014-01-09</oos:signDate>
...     <oos:versionNumber>0</oos:versionNumber>
...     <oos:foundation>
...       <oos:oosOrder>
...         <oos:notificationNumber>0365200021413000103</oos:notificationNumber>
...         <oos:lotNumber>1</oos:lotNumber>
...         <oos:placing>9</oos:placing>
...       </oos:oosOrder>
...     </oos:foundation>
...     <oos:customer>
...       <oos:regNum>03652000214</oos:regNum>
...       <oos:fullName>областное государственное бюджетное учреждение &quot;Служба хозяйственного обеспечения&quot;</oos:fullName>
...       <oos:inn>7017297271</oos:inn>
...       <oos:kpp>701701001</oos:kpp>
...     </oos:customer>
...     <oos:protocolDate>2013-12-25</oos:protocolDate>
...     <oos:documentBase>Протокол рассмотрения и оценки котировочных заявок №0365200021413000103-П от 25.12.2013; Протокол рассмотрения и оценки котировочных заявок №0365200021413000103-П от 25.12.2013</oos:documentBase>
...     <oos:price>230400</oos:price>
...   </contract>
... </export>
... """
>>> 
>>> doc = ET.fromstring(s)
>>> 
>>> ns = {'oss': 'http://zakupki.gov.ru/oos/types/1'}
>>> 
>>> doc.findall('.//oss:id', namespaces=ns)
[<Element '{http://zakupki.gov.ru/oos/types/1}id' at 0xb743020c>]
>>>

Можешь ещё посмотреть dip3. xml
Agiza
Решила допытать И xml, и себя. Вобщем, если дописать к коду сверху:
for c in a:  
    print (c.text)
То будет выводиться то, что надо.

Как будет время, обязательно изучу YAML. py.user.next, спасибо тебе за помощь
doza_and
Agiza
обязательно изучу YAML
Это xml наверное можно изучать. В yaml, json, pickle есть методы dump load, С очевидным функционалом, которые решают 99 процентов задач. Изучать то нечего.
Agiza
doza_and
Это xml наверное можно изучать. В yaml, json, pickle есть методы dump load, С очевидным функционалом, которые решают 99 процентов задач. Изучать то нечего.
Спасибо, посмотрю
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB