Pisałem niewielką funkcję, która wykorzystuje ElementTree i XPath, aby wyodrębnić zawartość tekstowych niektórych elementów w pliku XML:Python + Expat: Błąd na podmiotów
#!/usr/bin/env python2.5
import doctest
from xml.etree import ElementTree
from StringIO import StringIO
def parse_xml_etree(sin, xpath):
"""
Takes as input a stream containing XML and an XPath expression.
Applies the XPath expression to the XML and returns a generator
yielding the text contents of each element returned.
>>> parse_xml_etree(
... StringIO('<test><elem1>one</elem1><elem2>two</elem2></test>'),
... '//elem1').next()
'one'
>>> parse_xml_etree(
... StringIO('<test><elem1>one</elem1><elem2>two</elem2></test>'),
... '//elem2').next()
'two'
>>> parse_xml_etree(
... StringIO('<test><null>�</null><elem3>three</elem3></test>'),
... '//elem2').next()
'three'
"""
tree = ElementTree.parse(sin)
for element in tree.findall(xpath):
yield element.text
if __name__ == '__main__':
doctest.testmod(verbose=True)
Trzeci test nie powiedzie się z następujących wyjątek:
ExpatError: odniesienie do nieprawidłowej liczby znaków: linia nr 1, w kolumnie 13
Czy �
jednostka nielegalne XML? Niezależnie od tego, czy tak jest, pliki, które chcę analizować, zawierają to, i potrzebuję jakiegoś sposobu na ich przeanalizowanie. Jakieś sugestie dla innego analizatora składni niż Expat, czy ustawienia dla Expata, które pozwoliłyby mi to zrobić?
Aktualizacja: Odkryłem BeautifulSoup właśnie teraz, parser tag zupa opisanych poniżej w komentarzu odpowiedzi, i dla zabawy Wróciłem do tego problemu i próbował użyć go jako XML-czyszczącego przed ElementTree , ale sumiennie przekonwertował �
na nieprawidłowy bajt zerowy. :-)
cleaned_s = StringIO(
BeautifulStoneSoup('<test><null>�</null><elem3>three</elem3></test>',
convertEntities=BeautifulStoneSoup.XML_ENTITIES
).renderContents()
)
tree = ElementTree.parse(cleaned_s)
... plony
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 12
W moim konkretnym przypadku jednak tak naprawdę nie potrzebują parsowania XPath jako takiego, mógłbym już z samego BeautifulSoup i jego dość prosty styl adresu węzła: parsed_tree.test.elem1.contents[0]
.
Hm, tak, specyfikacja czyni to całkiem jasne. Dziękuję za dokładne odniesienie. – clacke
Rozumiem, że jest to stary wątek, ale specyfikacja mówi, co * literalne * znaki mogą pojawiać się tylko w XML. Bajtowa sekwencja nie jest * dosłownie * znakiem pustym, ale 4-znakową sekwencją * reprezentującą * bajt zerowy. Biorąc pod uwagę to rozróżnienie, jest legalne? Nie mogę znaleźć niczego w specyfikacji, która mówi, że * jest nielegalna. –
Ważne pytanie. Ale odpowiedź jest tutaj: http://www.w3.org/TR/REC-xml/#sec-references mówi "Znaki, do których odnosi się użycie referencji do znaków MUSZĄ pasować do produkcji Char." – clacke