Ошибки с условным etree lxml

#python #lxml #xml.etree

#python #lxml #xml.etree

Вопрос:

Я пытаюсь удалить все между, если между ними число 66:

Я получаю следующую ошибку: TypeError: аргумент типа ‘NoneType’ не может быть повторен … если element.tag == ‘answer’ и ‘-66’ в element.text:

Что в этом плохого? Любая помощь?

 #!/usr/local/bin/python2.7
# -*- coding: UTF-8 -*- 

from lxml import etree

planhtmlclear_utf=u"""
<questionaire>
<question>
<questiontext>What's up?</questiontext>
<answer></answer>
</question>
<question>
<questiontext>Cool?</questiontext>
<answer>-66</answer>
</question>
</questionaire>

"""

html = etree.fromstring(planhtmlclear_utf)
questions = html.xpath('/questionaire/question')
for question in questions:
    for element in question.getchildren():
        if element.tag == 'answer' and '-66' in element.text:
            html.xpath('/questionaire')[0].remove(question)
print etree.tostring(html) 
  

Ответ №1:

element.text, похоже, отсутствует на некоторых итерациях. Ошибка говорит о том, что он не может просмотреть None для «-66», поэтому сначала проверьте, что element.text не является None, например:

 html = etree.fromstring(planhtmlclear_utf)
questions = html.xpath('/questionaire/question')
for question in questions:
    for element in question.getchildren():   
        if element.tag == 'answer' and element.text and '-66' in element.text:
            html.xpath('/questionaire')[0].remove(question)
print etree.tostring(html) 
  

Строка, в которой он терпит неудачу в xml <answer></answer> , — это место, где между тегом нет текста.


Редактировать (для второй части вашей проблемы об объединении тегов):

Вы можете использовать BeautifulSoup так:

 from lxml import etree
import BeautifulSoup

planhtmlclear_utf=u"""
<questionaire>
<question>
<questiontext>What's up?</questiontext>
<answer></answer>
</question>
<question>
<questiontext>Cool?</questiontext>
<answer>-66</answer>
</question>
</questionaire>"""

html = etree.fromstring(planhtmlclear_utf)
questions = html.xpath('/questionaire/question')
for question in questions:
    for element in question.getchildren():   
        if element.tag == 'answer' and element.text and '-66' in element.text:
            html.xpath('/questionaire')[0].remove(question)

soup = BeautifulSoup.BeautifulStoneSoup(etree.tostring(html))
print soup.prettify()
  

С принтами:

 <questionaire>
 <question>
  <questiontext>
   What's up?
  </questiontext>
  <answer>
  </answer>
 </question>
</questionaire>
  

Вот ссылка, по которой вы можете скачать модуль BeautifulSoup.


Или, чтобы сделать это более компактным способом:

 from lxml import etree
import BeautifulSoup    

# abbreviating to reduce answer length...
planhtmlclear_utf=u"<questionaire>.........</questionaire>"

html = etree.fromstring(planhtmlclear_utf)
[question.getparent().remove(question) for question in html.xpath('/questionaire/question[answer/text()="-66"]')]
print BeautifulSoup.BeautifulStoneSoup(etree.tostring(html)).prettify()
  

Комментарии:

1. Может быть, вы можете помочь мне сделать еще один шаг: -P Теперь я получаю вывод: <вопросник> <вопрос> <текст вопроса> Что случилось? </questiontext> <ответ /> </question> </questionaire> ……. так что ответ показан не полностью… почему это так?

Ответ №2:

Альтернативой проверке, если element.text есть None , является уточнение вашего XPath:

 questions = html.xpath('/questionaire/question[answer/text()="-66"]')
for question in questions:
    question.getparent().remove(question)
  

Скобки [...] означают «такое, что». Итак

 question                          # find all question elements
[                                 # such that 
  answer                          # it has an answer subelement
    /text()                       # whose text 
  =                               # equals
  "-66"                           # "-66"
]
  

Комментарии:

1. это решает проблему, заключающуюся в том, что он не касается других элементов ответа… в приведенном выше примере я получаю вырезанные элементы ответа … но я не знаю почему… в любом случае с этим решением это работает!

2. нет, извините … он вырезает пустые теги ответов… почему это всегда происходит?

3. Я не уверен, что понимаю вопрос. Вы имеете <answer></answer> в виду, сокращается до <answer/> ? Все в порядке; они эквивалентны.

4. Да .. это то, что я имел в виду… но что я могу сделать, чтобы предотвратить это? Потому что мне нужны теги для правильного форматирования ..? Большое спасибо!

5. import lxml.html as lh . Затем lh.tostring(html) .