見出し画像

note でエクスポートしたXMLをPythonで読みやすくしたい(その6)

さてさてさてさて。

いよいよプログラミング実況中継風になってきました(笑)。
それもいいかも。

こちらの続きです。

(1)XMLファイルを読み込む
(2)読み込んだデータを木構造でアクセスする
(3)木構造の1Elementを1行で表示する
(4)noteのエクスポートファイルでテスト
(5)タグを置換
  item → details
  title → summary
  その他 → li
(6)Element.text を Element に格上げしようとして失敗。デバッグ中。

前回やったのはここまで。

『(6)Element.text を Element に格上げしよう』
をなんとか成功・・・できるのか。


noteでエクスポートしたXMLは、過去に書いた記事を含んでいる。それらの記事は当然のことながら html で記載されていて、エクスポートされたXMLは次のようになっている。

  • Element.tag が content:encoded

  • Element.text が記事内容

その text の記事内容は、もちろん html フォーマットである。

例えば、note 記事に

課題

のように見出しを書いたら、text には

<h2>課題</h2>

のような文字列が入っているわけだ。

XMLは、これを

課題

ではなく

<h2>課題</h2>

というように表示しようする。

結果、このような文字列に置き換えられてしまう。

&lt;h2&gt;課題&lt;/h2&gt;

htmlソースを読みたいわけではないので、

&lt;h2&gt;課題&lt;/h2&gt;

ではなく

<h2>課題</h2>

で出力したい。

たが、上手くいかない。

というのが、前回まで。


そもそも、XML に htmlフォーマットのテキストを解析させていることに無理があるように思えないでもない。
PythonにはXMLを解析するライブラリがあるくらいだもの、htmlだってあるんじゃね?

ということでこちらのPythonドキュメント『Python 標準ライブラリ』で探してみた。

ここで「html」を検索すると、あっさり出できたのである。
これこれ。

なので、変更してみた。

変更前
sub_tree = ET.XML(el.text)
変更後
from html.parser import HTMLParser
parser = HTMLParser()
sub_tree = ET.XML(el.text, parser)

import の位置は適当に調整するとして、要するに、
ElementTree の parser を html のものに置き換える
ということになる。

すると、前回あれだけドタバタした状況が一転、エラーなしであっさり通ってしまったのである。

そうすれば、前回修正したものも戻しておこう。

el.text = '<p>' + el.tag + '    ' + el.text + '</p>'
↓
el.text = '<p>' + el.tag + '<br>' + el.text + '</p>'

この時点では text を変換しただけで xml の tree は置き換えていない。

どうやって置き換える?

再び、「Element」のドキュメントを読んでみる。

すると・・・。
これか。

append(subelement)
要素 subelement を、要素の子要素の内部リストの末尾に追加します。subelementが Element でない場合、TypeError を送出します。

よし!
これを追加して・・・。

el.append(sub_tree)

実行~!

el.append(sub_tree)
TypeError: append() argument must be xml.etree.ElementTree.Element, not None

ん?
んんん?

引数は None はダメ?

え?
いや。
だから「sub_tree」を指定してるやん。

「sub_tree」はいったいどうなっとるんや。

text= <p>rss</p>
sub_tree= None
type(sub_tree)= <class 'NoneType'>

なんもなし?
はぁ?
どーゆーこと?

HTMLParser ってなんぞや。

HTMLParser
class html.parser.HTMLParser(*, convert_charrefs=True)
不正なマークアップをパースできるパーサーインスタンスを作成します。
〈中略〉
HTMLParser インスタンスは、HTML データが入力されると、開始タグ、終了タグ、およびその他の要素が見つかる度にハンドラーメソッドを呼び出します。各メソッドの挙動を実装するには HTMLParser サブクラスを使ってそれぞれを上書きして行います
このパーサーは終了タグが開始タグと一致しているか調べたり、外側のタグ要素が閉じるときに内側で明示的に閉じられていないタグ要素のタグ終了ハンドラーを呼び出したりはしません。

では、XMLParserは?

XMLParser
class xml.etree.ElementTree.XMLParser(*, target=None, encoding=None)
このクラスは、このモジュールの構成要素のうち、低水準のものです。効率的でイベントベースのXMLパースのため、xml.parsers.expat を使用します。feed() メソッドで XML データをインクリメンタルに受け取り、target オブジェクトのコールバックを呼び出すことで、パースイベントをプッシュ API に変換します。target が省略された場合、標準の TreeBuilder が使用されます。 encoding 1 が指定された場合、このあたいは XML ファイル内で指定されたエンコーディングを上書きします。

あー。

HTMLParserでは、Tree は作っていないのかぁ。
というか、もしかして空っぽ?
html も Tree にできないでもないだろうけど、 Tree の要求は大きくない。
かもしれない。

うーん、うーん、うーん。

どうすべ。

HTMLParser を継承して・・・、
TreeBuilder を使用・・・する?・・・というか、できる?

結構、大がかりになってくる?

そもそも、それが最短距離なのか?

代替案はあるのか?

・・・。

どうでもいいけど、Pythonって戻り値に何が返ってくるのか、わかりにくくね?

(つづく)


この記事が気に入ったらサポートをしてみませんか?