1
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
2
# vi: set ft=python sts=4 ts=4 sw=4 et:
3
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
4
#
5
#   See COPYING file distributed along with the NiBabel package for the
6
#   copyright and license terms.
7
#
8
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
9 33
"""
10
Thin layer around xml.etree.ElementTree, to abstract nibabel xml support.
11
"""
12

13 33
from io import BytesIO
14 33
from xml.etree.ElementTree import Element, SubElement, tostring  # noqa
15 33
from xml.parsers.expat import ParserCreate
16

17 33
from .filebasedimages import FileBasedHeader
18

19

20 33
class XmlSerializable(object):
21
    """ Basic interface for serializing an object to xml"""
22

23 33
    def _to_xml_element(self):
24
        """ Output should be a xml.etree.ElementTree.Element"""
25 0
        raise NotImplementedError()
26

27 33
    def to_xml(self, enc='utf-8'):
28
        """ Output should be an xml string with the given encoding.
29
        (default: utf-8)"""
30 33
        ele = self._to_xml_element()
31 33
        return '' if ele is None else tostring(ele, enc)
32

33

34 33
class XmlBasedHeader(FileBasedHeader, XmlSerializable):
35
    """ Basic wrapper around FileBasedHeader and XmlSerializable."""
36

37

38 33
class XmlParser(object):
39
    """ Base class for defining how to parse xml-based image snippets.
40

41
    Image-specific parsers should define:
42
        StartElementHandler
43
        EndElementHandler
44
        CharacterDataHandler
45
    """
46

47 33
    HANDLER_NAMES = ['StartElementHandler',
48
                     'EndElementHandler',
49
                     'CharacterDataHandler']
50

51 33
    def __init__(self, encoding='utf-8', buffer_size=35000000, verbose=0):
52
        """
53
        Parameters
54
        ----------
55
        encoding : str
56
            string containing xml document
57

58
        buffer_size: None or int, optional
59
            size of read buffer. None uses default buffer_size
60
            from xml.parsers.expat.
61

62
        verbose : int, optional
63
            amount of output during parsing (0=silent, by default).
64
        """
65 33
        self.encoding = encoding
66 33
        self.buffer_size = buffer_size
67 33
        self.verbose = verbose
68

69 33
    def _create_parser(self):
70
        """Internal function that allows subclasses to mess
71
        with the underlying parser, if desired."""
72

73 33
        parser = ParserCreate(encoding=self.encoding)  # from xml package
74 33
        parser.buffer_text = True
75 33
        if self.buffer_size is not None:
76 33
            parser.buffer_size = self.buffer_size
77 33
        return parser
78

79 33
    def parse(self, string=None, fname=None, fptr=None):
80
        """
81
        Parameters
82
        ----------
83
        string : str
84
            string containing xml document
85

86
        fname : str
87
            file name of an xml document.
88

89
        fptr : file pointer
90
            open file pointer to an xml documents
91
        """
92 33
        if int(string is not None) + int(fptr is not None) + int(fname is not None) != 1:
93 33
            raise ValueError('Exactly one of fptr, fname, string must be specified.')
94

95 33
        if string is not None:
96 33
            fptr = BytesIO(string)
97 33
        elif fname is not None:
98 0
            fptr = open(fname, 'r')
99

100 33
        parser = self._create_parser()
101 33
        for name in self.HANDLER_NAMES:
102 33
            setattr(parser, name, getattr(self, name))
103 33
        parser.ParseFile(fptr)
104

105 33
    def StartElementHandler(self, name, attrs):
106 0
        raise NotImplementedError
107

108 33
    def EndElementHandler(self, name):
109 0
        raise NotImplementedError
110

111 33
    def CharacterDataHandler(self, data):
112 0
        raise NotImplementedError

Read our documentation on viewing source code .

Loading