

以下のようなXMLファイルとpythonのファイルで実行しようとしているのですが、エラーが発生しどうすればエラーが消えるのかわかりません。また、文字化けも起きているのですが対処方法はありますか。（UTF-8を使用している）

**エラーコード（実行結果）**

[code]

    C:\Users\g21125\python_xml_ex>python all-element.py
    recipe
        dish
    Traceback (most recent call last):
      File "all-element.py", line 32, in <module>
        printAllElement(xdoc.documentElement)
      File "all-element.py", line 18, in printAllElement
        printAllElement(child, hierarchy+1)
      File "all-element.py", line 18, in printAllElement
        printAllElement(child, hierarchy+1)
      File "all-element.py", line 24, in printAllElement
        if data!='\n': print("{0}{1}".format(space, node.data))
    UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
    
    C:\Users\g21125\python_xml_ex>
    
[/code]

**sample.xml**

[code]

    <?xml version="1.0" encoding="UTF-8"?>
    <recipe name="パン" preparations-time="5分" cokking-time="3時間">
        <dish>基本的なパン</dish>
        <material quantity='3' unit='カップ'>小麦粉</material>
        <material quantity='0.25' unit='オンス'>イースト</material>
        <material quantity='1.5' unit='カップ'>水</material>
        <material quantity='1' unit='ティースプーン'>食塩</material>
        <point>
            <process>全ての材料を一緒にして混ぜます。</process>
            <process>十分にこねます。</process>
            <process>布で覆い、暖かい部屋で1時間そのままにしておきます。</process>
            <process>もう一度こねます。</process>
            <process>パン焼きの容器に入れます。</process>
            <process>布で覆い、暖かい部屋で1時間そのままにしておきます。</process>
            <process>オーブンに入れて温度を180℃にして30分間焼きます。</process>
        </point>
    </recipe>
    
[/code]

**all-element.py**

[code]

    # coding: utf-8
    # 全ての要素にアクセスする
    
    from xml.dom import minidom
    
    # 全ての要素のタグ名もしくはテキストを表示する
    def printAllElement(node, hierarchy=0):
        # スペース調整
        space = ''
        for i in range(hierarchy*4):
            space += ' '
    
        # エレメントノードの場合はタグ名を表示する
        if node.nodeType == node.ELEMENT_NODE:
            print("{0}{1}".format(space, node.tagName))
            # 再帰呼び出し
            for child in node.childNodes:
                printAllElement(child, hierarchy+1)
        # テキストもしくはコメントだった場合dataを表示する
        elif node.nodeType in [node.TEXT_NODE, node.COMMENT_NODE]:
            # スペースを取り除く
            data = node.data.replace(' ', '')
            # 改行のみではなかった時のみ表示する
            if data!='\n': print("{0}{1}".format(space, node.data))
    
    # sample.xmlファイルを読み込む
    xdoc = minidom.parse("sample.xml")
    
    # 全ての要素を表示
    printAllElement(xdoc.documentElement)
    
[/code]

**実行結果(正常終了)**

[code]

    recipe
        dish
            基本的なパン
        material
            小麦粉
        material
            イースト
        material
            水
        material
            食塩
        point
            process
                全ての材料を一緒にして混ぜます。
            process
                十分にこねます。
            process
                布で覆い、暖かい部屋で1時間そのままにしておきます。
            process
                もう一度こねます。
            process
                パン焼きの容器に入れます。
            process
                布で覆い、暖かい部屋で1時間そのままにしておきます。
            process
                オーブンに入れて温度を180℃にして30分間焼きます。
    
[/code]


CC BY-SA 3.0
2015-09-20T16:25:58.127
16805
2016-02-28T07:17:25.663
2015-09-20T20:56:41.760
9505
question
python xml
pythonでXMLを操作でのエラーが発生と文字化け②


# まぁ、Python3 に乗り替える、というのが一番簡単でしょうね  
~~  
if data != '\n': print("{0}{1}".format(space, node.data))

`str.format()` メソッドは unicode 文字列を str
文字列に変換(encode)しようとします。具体的には、`sys.getdefaultencoding()` で得られる encoding になります。

[code]

    >>> import sys
    >>> sys.getdefaultencoding()
    'ascii'
    
[/code]

特に設定がされていない場合(default encoding)は `ascii` ですので、`UnicodeEncodeError`
が発生してしまう事になります。

[code]

    >>> "{}".format(u"あ")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
    
[/code]

対応策はいくつかあります。

## UTF-8 に変換(unicode 文字列 → str 文字列)

Python の自動変換に頼るのではなく、明示的に node.data(unicode 文字列)を str 文字列(UTF-8)に変換します。

[code]

    if data != '\n':
      print("{0}{1}".format(space, node.data.encode('utf-8')))
    
[/code]

## Default encoding を変更

Default encoding を `ascii` から `UTF-8` に変更します。

[code]

              :
    import sys
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    # sample.xmlファイルを読み込む
    xdoc = minidom.parse("sample.xml")
              :
    
[/code]

## print 文(statement)を使用(sys.stdout の encoding 設定)

format() メソッドで書式を設定するのではなく、print 文を使います。

[code]

    if data != '\n': print "%s%s" % (space, node.data)
              :
    
    import sys
    import codecs
    sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
    
    # sample.xmlファイルを読み込む
    xdoc = minidom.parse("sample.xml")
              :
    
[/code]

標準出力(sys.stdout)の encoding を `UTF-8` に設定します。

[code]

    sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
    
[/code]

なお、上記の処理をソースコードに追加しなくても、環境変数 `PYTHONIOENCODING` を設定することによって同じ効果を得ることができます。

[code]

    $ PYTHONIOENCODING='UTF-8' python all-element.py
    
[/code]

> **PYTHONIOENCODING**
>
> If this is set before running the interpreter, it overrides the encoding
> used for stdin/stdout/stderr, in the syntax encodingname:errorhandler. The
> errorhandler part is optional and has the same meaning as in str.encode.  
>  ~~


CC BY-SA 3.0
2015-09-20T19:39:03.270
16809
2015-09-20T22:05:20.233
2015-09-20T22:05:20.233
16805
answer


次の行を

[code]

        if data!='\n': print("{0}{1}".format(space, node.data))
    
[/code]

このように書いて unicode指定にします

[code]

        if data!='\n': print(u"{0}{1}".format(space, node.data))
    
[/code]


CC BY-SA 3.0
2015-11-30T05:09:41.367
19461
2015-11-30T05:09:41.367
7837
16805
answer