Zanurkuj w Pythonie/Abstrakcyjne źródła wejścia: Różnice pomiędzy wersjami
Usunięta treść Dodana treść
Zdzichobot (dyskusja | edycje) zamiana {{Nawigacja|Python|->{{Nawigacja|Zanurkuj w Pythonie| Python/->../ |
poprawki |
||
Linia 1:
== Abstrakcyjne źródła wejścia ==
Linia 6 ⟶ 5:
Wiele funkcji, które wymagają jakiegoś źródła wejścia, mogłyby po prostu przyjmować jako argument nazwę pliku, następnie go otwierać, czytać, a na końcu go zamykać. Jednak tego nie robią. Zamiast działać w ten sposób, jako argument przyjmują obiekt pliku lub ''obiekt pliko-podobny''.
W najprostszym przypadku ''obiekt pliko-podobny'' jest dowolnym obiektem z metodą <
Powyżej opisaliśmy, w jaki sposób działają prawdziwe pliki. Jednak nie musimy się ograniczać do prawdziwych plików. Źródłem wejścia może być wszystko: plik na dysku, strona internetowa, czy nawet jakiś łańcuch znaków. Dopóki
Może się
|10.1 |tekst=
>>> from xml.dom import minidom
>>> fsock = open('binary.xml') #(1)
Linia 20 ⟶ 19:
>>> fsock.close() #(3)
>>> print xmldoc.toxml() #(4)
{{samp|<nowiki><?xml version="1.0" ?>
# Najpierw otwieramy plik z dysku. Otrzymujemy przez to obiekt pliku.
# Przekazujemy obiekt pliku do funkcji <
# Koniecznie wywołujemy metodę <
# Wywołując ze zwróconego dokumentu XML metodę <
}}
Dobrze, to wszystko wygląda jak kolosalne marnotrawstwo czasu. W końcu już wcześniej widzieliśmy, że <code>minidom.parse</code> może przyjąć jako argument nazwę pliku i wykonać całą robotę z otwieraniem i zamykaniem automatycznie. Prawdą jest, że jeśli chcemy sparsować lokalny plik, możemy przekazać nazwę pliku do <code>minidom.parse</code>, a funkcja ta będzie umiała mądrze to wykorzystać. Lecz zauważmy jak podobne i łatwe jest także parsowanie dokumentu XML pochodzącego bezpośrednio z Internetu.
{{Python/Przykład
|10.2|Parsowanie XML-a z URL-a
|tekst=
>>> import urllib
>>> usock = urllib.urlopen(<nowiki>'http://slashdot.org/slashdot.rdf'</nowiki>) #(1)
>>> xmldoc = minidom.parse(usock) #(2)
>>> usock.close() #(3)
>>> print xmldoc.toxml() #(4)
{{samp|<nowiki><?xml version="1.0" ?>
# Jak już zaobserwowaliśmy w poprzednim rozdziale, <
# Teraz przekazujemy ten ''obiekt pliko-podobny'' do <
# Jak tylko ''obiekt pliko-podobny'', który podarował nam <
# Przy okazji, ten URL jest prawdziwy i on naprawdę jest dokumentem XML. Reprezentuje on aktualne nagłówki, techniczne newsy i plotki w [http://slashdot.org/ Slashdot].
}}
{{Python/Przykład
|10.3|Parsowanie XML-a z łańcucha znaków (prosty sposób, ale mało elastyczny)
|tekst=
>>> contents = "<nowiki><grammar><ref id='bit'><p>0</p><p>1</p></ref></grammar></nowiki>"
>>> xmldoc = minidom.parseString(contents) #(1)
>>> print xmldoc.toxml()
{{samp|<nowiki><?xml version="1.0" ?>
<grammar><ref id="bit"><p>0</p><p>1</p></ref></grammar></nowiki>}}
# <
}}
OK, to możemy korzystać z funkcji <
Gdyby tylko był sposób, aby zmienić łańcuch znaków na obiekt ''pliko-podobny'', to moglibyśmy po prostu przekazać ten obiekt do <
{{Python/Przykład
|10.4|Wprowadzenie do <code>StringIO</code>
|tekst=
>>> contents = "<nowiki><grammar><ref id='bit'><p>0</p><p>1</p></ref></grammar></nowiki>"
>>> import StringIO
>>> ssock = StringIO.StringIO(contents) #(1)
>>> ssock.read() #(2)
{{samp|<nowiki>"<grammar><ref id='bit'><p>0</p><p>1</p></ref></grammar>"</nowiki>}}
>>> ssock.read() #(3)
{{samp|<nowiki>''</nowiki>}}
>>> ssock.seek(0) #(4)
>>> ssock.read(15) #(5)
{{samp|<nowiki>'<grammar><ref i'</nowiki>}}
>>> ssock.read(15)
{{samp|<nowiki>"d='bit'><p>0</p"</nowiki>}}
>>> ssock.read()
{{samp|<nowiki>'><p>1</p></ref></grammar>'</nowiki>}}
>>> ssock.close() #(6)
# Moduł <
# Teraz już mamy ''obiekt pliko-podobny'' i możemy robić wszystkie możliwe ''pliko-podobne'' operacje. Na przykład <
# Wywołując ponownie <
# Możemy jawnie przesunąć się do początku napisu, podobnie jak możemy się przesunąć w pliku, wykorzystując metodę <
# Możemy także czytać fragmentami łańcuch znaków,
# Za każdym razem, kiedy wywołamy <
}}
{{Python/Przykład
|10.5|Parsowanie XML-a z łańcucha znaków (sposób z obiektem pliko-podobnym)
|tekst=
>>> contents = "<nowiki><grammar><ref id='bit'><p>0</p><p>1</p></ref></grammar></nowiki>"
>>> ssock = StringIO.StringIO(contents)
>>> xmldoc = minidom.parse(ssock) #(1)
>>> ssock.close()
>>> print xmldoc.toxml()
{{samp|<nowiki><?xml version="1.0" ?></nowiki>}}
{{samp|<nowiki><grammar><ref id="bit"><p>0</p><p>1</p></ref></grammar></nowiki>}}
# Teraz możemy przekazać obiekt pliko-podobny (w rzeczywistości instancję <
}}
To już wiemy, jak za pomocą pojedynczej funkcji, <code>minidom.parse</code>, sparsować dokument XML przechowywany na stronie internetowej, lokalnym pliku, czy w łańcuchu znaków. Dla strony internetowej wykorzystamy <code>urlopen</code>, aby dostać ''obiekt pliko-podobny''; dla lokalnego pliku, wykorzystamy <code>open</code>; a w przypadku łańcucha znaków skorzystamy z <code>StringIO</code>. Lecz teraz pójdźmy trochę do przodu i uogólnijmy też te różnice.
{{Python/Przykład
|tekst=
<pre>
def
# próbuje otworzyć za
import urllib
try:
return urllib.urlopen(source) #(2)
except (IOError, OSError):
pass
# traktuje source jako łańcuch znaków z danymi
import StringIO
return StringIO.StringIO(str(source)) #(4)
</pre>
# Funkcja <code>openAnything</code> przyjmuje pojedynczy argument, <code>source</code>, i zwraca ''obiekt pliko-podobny''. <code>source</code> jest łańcuchem znaków o różnym charakterze. Może się odnosić do adresu URL (np. <code><nowiki>'http://slashdot.org/slashdot.rdf'</nowiki></code>), może być globalną lub lokalną ścieżką do pliku (np. <code>'binary.xml'</code>), czy też łańcuchem znaków przechowującym dokument XML, który ma zostać sparsowany.
# Najpierw sprawdzamy, czy <code>source</code> jest URL-em. Robimy to brutalnie: próbujemy otworzyć to jako URL i cicho pomijamy błędy spowodowane próbą otworzenia czegoś, co nie jest URL-em. Jest to właściwie eleganckie w tym sensie, że jeśli <code>urllib</code> będzie kiedyś obsługiwał nowe typy URL-i, nasz program także je obsłuży i to bez konieczności zmiany kodu. Jeśli <code>urllib</code> jest w stanie otworzyć <code>source</code>, to <code>return</code> wykopie nas bezpośrednio z funkcji i poniższe instrukcje <code>try</code> nie będą nigdy wykonywane.
# W innym przypadku, gdy <code>urllib</code> wrzasnął na nas i powiedział, że <code>source</code> nie jest poprawnym URL-em, zakładamy, że jest to ścieżka do pliku znajdującego się na dysku i próbujemy go otworzyć. Ponownie, nic nie robimy, by sprawdzić, czy <code>source</code> jest poprawną nazwą pliku (zasady określające poprawność nazwy pliku są znacząco różne na różnych platformach, dlatego prawdopodobnie i tak byśmy to źle zrobili). Zamiast tego, na ślepo otwieramy plik i cicho pomijamy wszystkie błędy.
# W tym miejscu zakładamy, że <code>source</code> jest łańcuchem znaków, który przechowuje dokument XML (ponieważ nic innego nie zadziałało), dlatego wykorzystujemy <code>StringIO</code>, aby utworzyć ''obiekt pliko-podobny'' i zwracamy go. (Tak naprawdę, ponieważ wykorzystujemy funkcję <code>str</code>, <code>source</code> nie musi być nawet łańcuchem znaków; może być nawet dowolnym obiektem, a z którego zostanie wykorzystana jego tekstowa reprezentacja, a która jest zdefiniowana przez specjalną metodę <code>__str__</code>.)
}}
Teraz możemy wykorzystać funkcję <code>openAnything</code> w połączeniu z <code>minidom.parse</code>, aby utworzyć funkcję, która przyjmuje źródło <code>source</code>, które w jakiś sposób odwołuje się do dokumentu XML (może to robić za pomocą adresu URL, lokalnego pliku, czy też dokumentu przechowywanego jako łańcuch znaków), i parsuje je.
{{Python/Przykład
|10.7|Wykorzystanie <code>openAnything</code> w {{Python/Src|kgp/kgp.py|kgp.py}}
|tekst=
<pre>
class KantGenerator:
def _load(self, source):
sock = toolbox.openAnything(source)
xmldoc = minidom.parse(sock).documentElement
sock.close()
return xmldoc
</pre>
}}
<noinclude>
{{Nawigacja|Zanurkuj w Pythonie|
[[../Przetwarzanie XML-a - podsumowanie|
[[../Standardowy strumień wejścia, wyjścia i błędów
}}
{{Podświetl|py}}
</noinclude>
|