Exemple #1
0
def get_report_section(html_report,
                       component_id,
                       container_wrapper_format=container_format):
    """Get specific report section from InaSAFE analysis summary report.

    :param html_report: The html report.
    :type html_report: basestring

    :param component_id: The component key.
    :type component_id: str

    :param container_wrapper_format: A string format for wrapping the section.
    :type container_wrapper_format: basestring

    :return: Requested report section as an html.
    :rtype: basestring
    """
    no_element_error = tr('No element match the tag or component id.')

    root_element, dict_of_elements = ET.XMLID(html_report)
    section_element = dict_of_elements.get(component_id)

    if section_element:
        requested_section = container_wrapper_format.format(
            section_content=str(ET.tostring(section_element)))
        return requested_section
    else:
        return no_element_error
 def test_dump(self, mock_stdout):  # to stdout
     root, id_map = ET.XMLID(open(self.xml_file).read())
     ET.dump(id_map['S001'])
     self.assertEqual(
         mock_stdout.getvalue(),
         '<student id="S001" lang="English" name="Jeremy">\n      <weight>65</weight>\n      <height>178</height>\n      <cname>Jeremy Kao</cname>\n    </student>\n  \n'
     )
Exemple #3
0
 def __init__(self, fname, mode=None):
     (root, ext) = os.path.splitext(fname)
     self.h5path = root + '.h5'
     self.xdmfpath = root + (ext if ext else '.xmf')
     self.h5fp = h5py.File(self.h5path, mode)
     (self.xml, self.xmlids) = ET.XMLID(XDMFSTR)
     self.dim = (0, 0)
 def test_xmlid(self):
     root, id_map = ET.XMLID(open(self.xml_file).read())
     self.assertIsInstance(root, ET.Element)
     self.assertEqual(root.tag, 'data')
     self.assertEqual(len(id_map), 2)
     self.assertEqual(id_map['S001'].get('name'), 'Jeremy')
     self.assertEqual(id_map['J001'].get('name'), 'Judy')
Exemple #5
0
 def add_attribute(self, name, data):
     self.h5fp.create_dataset(name, data=data, dtype='f')
     (attrxml, ids) = ET.XMLID(XDMFATTR)
     ids['attr'].set('Name', name)
     ids['item'].set('Dimensions', '1 %d %d' % data.shape)
     ids['item'].text = '%s:/%s' % (os.path.basename(
         self.h5fp.filename), name)
     self.xmlids['grid'].append(attrxml)
     self.dim = np.maximum(self.dim, data.shape)
Exemple #6
0
 def update(self):
     request = requests.get('https://www.ndbc.noaa.gov/activestations.xml')
     parsed = ElementTree.XMLID(request.content)
     elements = parsed[1]
     for stationID, element in elements.items():
         attributes = element.attrib
         name = attributes['name']
         potentialBuoy = {'station_id': stationID, 'name': name}
         print potentialBuoy
         potentialBuoyObject = PotentialBuoy(**potentialBuoy)
         self.db.potentialBuoys.update({'station_id': stationID},
                                       potentialBuoyObject.mongoDB(),
                                       upsert=True)
Exemple #7
0
 def add_scalar(self, name, data):
     dim = data.shape
     if len(dim) == 1:
         dim = (1, dim[0])
     self.h5fp.create_dataset(name, data=data, dtype='f')
     (attrxml, ids) = ET.XMLID(XDMFATTR)
     ids['attr'].set('Name', name)
     ids['attr'].set('AttributeType', 'Scalar')
     ids['item'].set('Dimensions', '1 %d %d' % dim)
     ids['item'].text = '%s:/%s' % (os.path.basename(
         self.h5fp.filename), name)
     self.xmlids['grid'].append(attrxml)
     self.dim = np.maximum(self.dim, dim)
Exemple #8
0
 def add_vector(self, name, data):
     n = data.shape[-1]
     dim = data.shape[0:-1]
     if len(dim) == 1:
         dim = (dim[0], 1)
     self.h5fp.create_dataset(name, data=data, dtype='f')
     (attrxml, ids) = ET.XMLID(XDMFATTR)
     ids['attr'].set('Name', name)
     ids['attr'].set('AttributeType', 'Vector')
     ids['item'].set('Dimensions', '%d %d %d' % (dim[0], dim[1], n))
     ids['item'].text = '%s:/%s' % (os.path.basename(
         self.h5fp.filename), name)
     self.xmlids['grid'].append(attrxml)
     self.dim = np.maximum(self.dim, dim)
Exemple #9
0
# Set id for the annotations
for i, t in enumerate(ax.texts):
    t.set_gid('tooltip_%d' % i)

# Save the figure in a fake file object
ax.set_xlim(-30, 30)
ax.set_ylim(-30, 30)
ax.set_aspect('equal')

f = StringIO()
plt.savefig(f, format="svg")

# --- Add interactivity ---

# Create XML tree from the SVG file.
tree, xmlid = ET.XMLID(f.getvalue())
tree.set('onload', 'init(evt)')

# Hide the tooltips
for i, t in enumerate(ax.texts):
    el = xmlid['tooltip_%d' % i]
    el.set('visibility', 'hidden')

# Assign onmouseover and onmouseout callbacks to patches.
for i, t in enumerate(ax.patches):
    el = xmlid['patch_%d' % i]
    el.set('onmouseover', "ShowTooltip(this)")
    el.set('onmouseout', "HideTooltip(this)")

# This is the script defining the ShowTooltip and HideTooltip functions.
script = """
Exemple #10
0
def read_from_string(input_str):
    """Read a Kdenlive project (MLT XML)
    Kdenlive uses a given MLT project layout, similar to Shotcut,
    combining a "main_bin" playlist to organize source media,
    and a "global_feed" tractor for timeline.
    (in Kdenlive 19.x, timeline tracks include virtual sub-track, unused for now)"""
    mlt, byid = ET.XMLID(input_str)
    profile = mlt.find('profile')
    rate = (float(profile.get('frame_rate_num')) /
            float(profile.get('frame_rate_den', 1)))
    timeline = otio.schema.Timeline(
        name=mlt.get('name', 'Kdenlive imported timeline'))

    maintractor = mlt.find("tractor[@global_feed='1']")
    for maintrack in maintractor.findall('track'):
        if maintrack.get('producer') == 'black_track':
            continue
        subtractor = byid[maintrack.get('producer')]
        track = otio.schema.Track(
            name=read_property(subtractor, 'kdenlive:track_name'))
        if bool(read_property(subtractor, 'kdenlive:audio_track')):
            track.kind = otio.schema.TrackKind.Audio
        else:
            track.kind = otio.schema.TrackKind.Video
        for subtrack in subtractor.findall('track'):
            playlist = byid[subtrack.get('producer')]
            for item in playlist.iter():
                if item.tag == 'blank':
                    gap = otio.schema.Gap(
                        duration=time(item.get('length'), rate))
                    track.append(gap)
                elif item.tag == 'entry':
                    producer = byid[item.get('producer')]
                    service = read_property(producer, 'mlt_service')
                    available_range = otio.opentime.TimeRange.range_from_start_end_time(
                        start_time=time(producer.get('in'), rate),
                        end_time_exclusive=(
                            time(producer.get('out'), rate) +
                            otio.opentime.RationalTime(1, rate)),
                    )
                    source_range = otio.opentime.TimeRange.range_from_start_end_time(
                        start_time=time(item.get('in'), rate),
                        end_time_exclusive=(
                            time(item.get('out'), rate) +
                            otio.opentime.RationalTime(1, rate)),
                    )
                    # media reference clip
                    reference = None
                    if service in [
                            'avformat', 'avformat-novalidate', 'qimage'
                    ]:
                        reference = otio.schema.ExternalReference(
                            target_url=read_property(producer,
                                                     'kdenlive:originalurl')
                            or read_property(producer, 'resource'),
                            available_range=available_range)
                    elif service == 'color':
                        reference = otio.schema.GeneratorReference(
                            generator_kind='SolidColor',
                            parameters={
                                'color': read_property(producer, 'resource')
                            },
                            available_range=available_range)
                    clip = otio.schema.Clip(name=read_property(
                        producer, 'kdenlive:clipname'),
                                            source_range=source_range,
                                            media_reference=reference
                                            or otio.schema.MissingReference())
                    for effect in item.findall('filter'):
                        kdenlive_id = read_property(effect, 'kdenlive_id')
                        if kdenlive_id in [
                                'fadein', 'fade_from_black', 'fadeout',
                                'fade_to_black'
                        ]:
                            clip.effects.append(
                                otio.schema.Effect(
                                    effect_name=kdenlive_id,
                                    metadata={
                                        'duration':
                                        time(effect.get('out'), rate) - time(
                                            effect.get('in',
                                                       producer.get('in')),
                                            rate)
                                    }))
                        elif kdenlive_id in ['volume', 'brightness']:
                            clip.effects.append(
                                otio.schema.Effect(effect_name=kdenlive_id,
                                                   metadata={
                                                       'keyframes':
                                                       read_keyframes(
                                                           read_property(
                                                               effect,
                                                               'level'), rate)
                                                   }))
                    track.append(clip)
        timeline.tracks.append(track)

    for transition in maintractor.findall('transition'):
        kdenlive_id = read_property(transition, 'kdenlive_id')
        if kdenlive_id == 'wipe':
            timeline.tracks[int(read_property(transition, 'b_track')) -
                            1].append(
                                otio.schema.Transition(
                                    transition_type=otio.schema.
                                    TransitionTypes.SMPTE_Dissolve,
                                    in_offset=time(transition.get('in'), rate),
                                    out_offset=time(transition.get('out'),
                                                    rate)))

    return timeline
Exemple #11
0
def read_from_string(input_str):
    """Read a Kdenlive project (MLT XML)
    Kdenlive uses a given MLT project layout, similar to Shotcut,
    combining a "main_bin" playlist to organize source media,
    and a "global_feed" tractor for timeline.
    (in Kdenlive 19.x, timeline tracks include virtual sub-track, unused for now)"""
    DBG('read_from_string() BEGIN --------------------------------------------------'
        )
    mlt, byid = ET.XMLID(input_str)
    profile = mlt.find('profile')
    rate = (float(profile.get('frame_rate_num')) /
            float(profile.get('frame_rate_den', 1)))
    timeline = otio.schema.Timeline(
        name=mlt.get('name', 'Kdenlive imported timeline'))

    playlist_main_bin = mlt.find("playlist[@id='main_bin']")
    DBG('playlist_main_bin:', playlist_main_bin)
    if playlist_main_bin is not None:
        DBG('playlist_main_bin:')
        ET.dump(playlist_main_bin)

        guides = playlist_main_bin.find(
            "property[@name='kdenlive:docproperties.guides']")
        if guides is not None:
            DBG('guides:')
            ET.dump(guides)
            DBG('guides text:', guides.text)
            timeline.metadata['guides'] = json.loads(guides.text)
            for guide in timeline.metadata['guides']:
                DBG('guide:', guide)
                if 'pos' in guide:
                    DBG('time:', time(str(guide['pos']), rate))
                    guide['pos'] = time(str(guide['pos']), rate)
            DBG('timeline.metadata:', timeline.metadata)

        groups = playlist_main_bin.find(
            "property[@name='kdenlive:docproperties.groups']")
        if groups is not None:
            DBG('groups:')
            ET.dump(groups)
            DBG('groups text:', groups.text)
            timeline.metadata['groups'] = json.loads(groups.text)
            DBG('timeline.metadata:', timeline.metadata)

    maintractor = mlt.find("tractor[@global_feed='1']")
    for maintrack in maintractor.findall('track'):
        if maintrack.get('producer') == 'black_track':
            continue
        subtractor = byid[maintrack.get('producer')]
        track = otio.schema.Track(
            name=read_property(subtractor, 'kdenlive:track_name'))
        if bool(read_property(subtractor, 'kdenlive:audio_track')):
            track.kind = otio.schema.TrackKind.Audio
        else:
            track.kind = otio.schema.TrackKind.Video
        for subtrack in subtractor.findall('track'):
            playlist = byid[subtrack.get('producer')]

            DBG('SUBTRACK: ', subtrack)
            DBG('PLAYLIST: ', playlist)
            for item in playlist.iter():
                DBG('PLAYLIST ITEM:', ET.dump(item))
                if item.tag == 'blank':
                    gap = otio.schema.Gap(
                        duration=time(item.get('length'), rate))
                    track.append(gap)
                elif item.tag == 'entry':
                    producer = byid[item.get('producer')]
                    service = read_property(producer, 'mlt_service')
                    DBG('producer:')
                    ET.dump(producer)
                    available_range = None
                    if 'in' in producer.keys() and 'out' in producer.keys():
                        available_range = otio.opentime.TimeRange(
                            start_time=time(producer.get('in'), rate),
                            duration=time(producer.get('out'), rate) -
                            time(producer.get('in'), rate) +
                            otio.opentime.RationalTime(1, rate))
                    source_range = otio.opentime.TimeRange(
                        start_time=time(item.get('in'), rate),
                        duration=time(item.get('out'), rate) -
                        time(item.get('in'), rate) +
                        otio.opentime.RationalTime(1, rate))
                    props = {}
                    for prop in producer.findall('property'):
                        #DBG('prop: ' + prop.get('name') + ' -> ' + prop.text)
                        #DBG(ET.dump(prop))

                        # TODO: Folders are not supported yet
                        if prop.get('name') == 'kdenlive:folderid':
                            continue
                        props[prop.get('name')] = prop.text
                    # media reference clip
                    reference = None
                    if service in [
                            'avformat', 'avformat-novalidate', 'qimage',
                            'consumer', 'xml'
                    ]:
                        reference = otio.schema.ExternalReference(
                            target_url=read_property(producer,
                                                     'kdenlive:originalurl')
                            or read_property(producer, 'resource'),
                            available_range=available_range)
                    elif service == 'color':
                        reference = otio.schema.GeneratorReference(
                            generator_kind='SolidColor',
                            parameters={
                                'color': read_property(producer, 'resource')
                            },
                            available_range=available_range)
                    elif service == 'kdenlivetitle':
                        reference = otio.schema.GeneratorReference(
                            generator_kind=service,
                            available_range=available_range)
                    clip = otio.schema.Clip(name=read_property(
                        producer, 'kdenlive:clipname'),
                                            source_range=source_range,
                                            metadata=props,
                                            media_reference=reference
                                            or otio.schema.MissingReference())
                    DBG('item:')
                    DBG(ET.dump(item))
                    for effect in item.findall('filter'):
                        DBG('effect:')
                        DBG(ET.dump(effect))
                        kdenlive_id = read_property(effect, 'kdenlive_id')
                        if kdenlive_id in [
                                'fadein', 'fade_from_black', 'fadeout',
                                'fade_to_black'
                        ]:
                            clip.effects.append(
                                otio.schema.Effect(
                                    effect_name=kdenlive_id,
                                    metadata={
                                        'duration':
                                        time(effect.get('out'), rate) - time(
                                            effect.get('in',
                                                       producer.get('in')),
                                            rate)
                                    }))
                        elif kdenlive_id in ['volume', 'brightness']:
                            clip.effects.append(
                                otio.schema.Effect(effect_name=kdenlive_id,
                                                   metadata={
                                                       'keyframes':
                                                       read_keyframes(
                                                           read_property(
                                                               effect,
                                                               'level'), rate)
                                                   }))
                        else:
                            props = {}
                            for prop in effect.findall('property'):
                                #DBG('prop: ' + prop.get('name') + ' -> ' + prop.text)
                                #DBG(ET.dump(prop))
                                props[prop.get('name')] = prop.text
                            DBG('props:', props)
                            clip.effects.append(
                                otio.schema.Effect(effect_name=kdenlive_id,
                                                   metadata=props))
                    DBG('reference:', reference)
                    DBG('effects:', item.findall('filter'))
                    track.append(clip)
        timeline.tracks.append(track)

    for transition in maintractor.findall('transition'):
        kdenlive_id = read_property(transition, 'kdenlive_id')
        if kdenlive_id == 'wipe':
            timeline.tracks[int(read_property(transition, 'b_track')) -
                            1].append(
                                otio.schema.Transition(
                                    transition_type=otio.schema.
                                    TransitionTypes.SMPTE_Dissolve,
                                    in_offset=time(transition.get('in'), rate),
                                    out_offset=time(transition.get('out'),
                                                    rate)))

    DBG('read_from_string() END --------------------------------------------------'
        )
    return timeline
Exemple #12
0
def plotMilestones(milestones, prefix):
  import xml.etree.ElementTree as ET
  from io import BytesIO

  fig, ax = plt.subplots()
  ET.register_namespace("", "http://www.w3.org/2000/svg")

  max_x = 0
  max_y = 0
  index = 0
  for m in milestones:
    index = m.add_labeled_patches(ax, index)
    max_x = max(max_x, m.x)
    max_y = max(max_y, m.y)

    # these are matplotlib.patch.Patch properties
    props = dict(boxstyle='round', facecolor=m.rect.get_facecolor(), alpha=0.63)

    # place a text box in upper left in axes coords
    header = ax.text(-2, m.y+0.2, m.name, color="white",
                     verticalalignment='bottom', bbox=props)

  ax.set_xlim(-2, max_x + 1)
  ax.set_ylim(0, max_y + 1)
  xticks = []
  xlabels = []
  for i in range(0, max_x+1, 2):
    xticks.append(i)
    xlabels.append("Q%d" % (i/2))
  ax.set_xticks(xticks)
  ax.set_xticklabels(xlabels)
  ax.set_aspect('equal')
  f = BytesIO()
  plt.savefig(f, format="svg")
  # Insert the script at the top of the file and save it.
  tree, xmlid = ET.XMLID(f.getvalue())
  tree.set('onload', 'init(evt)')
  # This is the script defining the ShowTooltip and HideTooltip functions.
  script = """
    <script type="text/ecmascript">
    <![CDATA[

    function init(evt) {
        if ( window.svgDocument == null ) {
            svgDocument = evt.target.ownerDocument;
            }
        }

    function ShowTooltip(obj) {
        var cur = obj.id.split("_")[1];
        var tip = svgDocument.getElementById('mytooltip_' + cur);
        tip.setAttribute('visibility',"visible")
        }

    function HideTooltip(obj) {
        var cur = obj.id.split("_")[1];
        var tip = svgDocument.getElementById('mytooltip_' + cur);
        tip.setAttribute('visibility',"hidden")
        }

    ]]>
    </script>
    """


  index = 0
  for m in milestones:
    index = m.add_tooltips(ax, xmlid, index)

  tree.insert(0, ET.XML(script))
  name = "%s.svg" % prefix
  ET.ElementTree(tree).write(name)
  return name
def et_func():
    '''
    ElementTree
    '''
    # 创建
    # xml.etree.ElementTree.parse(source, parser=None)  // xml解析到元素树中, source:文件名 / file-obj
    tree = et.parse(path)

    # xml.etree.ElementTree.SubElement(parent, tag, attrib={}, **extra) // 穿件元素实例, parent:父元素, tag:子元素名称, attrib:{attr:value}, extra:其他关键字属性
    elem = et.SubElement(elem, "name", attrib={"show": "yes"})
    # xml.etree.ElementTree.fromstring(text) // 从字符换解析xml, 返回Element实例
    elem = et.fromstring(data)
    # xml.etree.ElementTree.fromstringlist(sequence, parser=None) // 同fromstring
    elem = et.fromstringlist(data)
    # xml.etree.ElementTree.XML(text, parser=None) // 同fromstring
    elem = et.XML(data)
    # xml.etree.ElementTree.XMLID(text, parser=None) // 从字符串中解析xml, 并返回(元素, 字典)
    elem, dicts = et.XMLID(data)
    # xml.etree.ElementTree.Comment(text=None) // 注释元素, text:注释内容(bytes / Unicode字符串), XMLParser跳过注释,ElementTree只包含注释结点
    elem = et.Comment(r"注释")
    # xml.etree.ElementTree.ProcessingInstruction(target, text=None) // PI元素, target:PI目标字符串, text:PI内容字符串, 返回元素实例, XMLParser跳过该元素, ElementTree只包含节点
    # xml.etree.ElementTree.register_namespace(prefix, uri) // 注册命名空间前缀, prefix:前缀, uri:命名空间
    et.register_namespace("web", "http://luzhuo.me")

    # xml递增的方式解析到元素树中(适合大文件), source:文件名/file-obj, events:要报告的事件("start", "end"(默认), "start-ns", "end-ns), parser:可选的解析器(XMLParser的子类)
    # xml.etree.ElementTree.iterparse(source, events=None)
    events, elem = et.iterparse(path)

    # xml.etree.ElementTree.dump(elem) // 将元素树写成普通的xml文件
    et.dump(elem)
    # xml字符串表示形式, method:"xml"(默认)."html"."text"
    # xml.etree.ElementTree.tostring(element, encoding="us-ascii", method="xml", *, short_empty_elements=True)
    strs = et.tostring(elem, encoding="utf-8")
    # xml.etree.ElementTree.tostringlist(element, encoding="us-ascii", method="xml", *, short_empty_elements=True) // 同tostring
    strs = et.tostringlist(elem)

    boolean = et.iselement(elem)  # 是否是元素对象

    # --- Element 对象 ---
    # class xml.etree.ElementTree.Element(tag, attrib={}, ** extra) // 元素类, tag:bytes/Unicode字符串, attrib:{attr:value}

    elem.tag  # 元素名
    elem.text  # 元素内容(标签的内容<a>text</a>)
    elem.tail  # 元素内容(标签之后的内容</a>text)
    dicts = elem.attrib  # 属性字典
    elem.clear()  # 删除所有元素,属性
    elem.get("age", default=None)  # 获取属性的值
    key, value = elem.items()  # 元素属性列表(key, value)返回
    elem.keys()  # 元素的属性列表
    elem.set(key, value)  # 设置元素的属性
    elem.append(elem)  # 添加元素到末尾(直接下级)
    # elem.extend(elem)  # 添加元素到末尾, 源码是调用_children列表.extentd()方式添加元素,不知为何.append()有用,而extentd()无效果
    # find(match, namespaces=None) // 匹配(直接下级)第一个子元素, match:元素名 / XPath, namespaces:命名空间
    elem = elem.find("root")
    # findall(match, namespaces=None) // 匹配(直接下级)所有子元素, match:元素名 / XPath
    elems = elem.findall("root")
    # findtext(match, default=None, namespaces=None) // 匹配(直接下级)第一个子元素的文本
    texts = elem.findtext("root")
    elem.insert(1, elem)  # 插入子元素, index:位置, subelement:子元素
    # iter(tag=None)  # 指定(所有下级)元素名的迭代器(深度优先)
    elem.iter("root")
    elem.iterfind("root")  # 匹配(直接下级)所有子元素, 返回迭代器
    elem.itertext()  # 文本迭代器(所有下级)
    elem.remove(elem)  # 删除子元素

    # --- ElementTree 对象 ---
    # ElementTree包装类, 表示整个元素的层次结构, element:根元素, file:如果给定,将生成初始化树
    # class xml.etree.ElementTree.ElementTree(element=None, file=None)
    et_ = et.ElementTree(elem)
    # parse(source, parser=None) // 解析xml到元素树, source:文件名 / file-obj
    et_ = et_.parse(path)

    et_.getroot()  # 获取根元素
    et_.__setroot(elem)  # 替换根元素
    et_._find("root", namespaces=None)  # 同Element.find()
    et_._findall("root", namespaces=None)  #同Element.findall()
    et_._findtext("root", default=None, namespaces=None)  # Element.findtext()

    et_.iter(tag=None)  # Element.iter()
    # iterfind(match, namespaces=None) // Element.iterfind()
    et_.iterfind("root")

    # 将元素树写入文件, file:文件名/file-obj, xml_declaration:是否显示声明信息, default_namespace:命名空间("xmlns"), method:"xml"(默认)/"html"/"text", short_empty_elements:是否自闭标签(默认True)
    # write(file, encoding="us-ascii", xml_declaration=None, default_namespace=None, method="xml", *, short_empty_elements=True)
    et_.write("new.xml", encoding="utf-8", xml_declaration=True)
    for (name, value) in sorted(node.attrib.items()):
        print "  %-4s = '%s'" % (name, value)
    for child in node:
        show_node(child)
    return


# unlike with parse() the returned value is an Element instead of an ElementTree
# Elements can be iterated upon directly instead of using iterparse()
for elem in parsed:
    show_node(elem)
print

# for structures XML that uses the id attribute it identify unique nodes there is XMLID()
print "Using XMLID():"
tree, id_map = ElementTree.XMLID(xml_string_to_parse)
for (key, value) in sorted(id_map.items()):
    print "  %-4s = '%s'" % (key, value)
print

## 7.6.8 Building Documents wih Element Nodes
# ElementTree is also capable of creating well-formed XML documents from Element objects
# The Element class can produce a serialized form of its contents which can then be stored
# There are three helper functions useful when creating a hierarchy of Element nodes
# Element() creates a standard node
# SubElement() attached a new node to a parent
# Comment() creates a node that serializes using XML's comment syntax

top = Element('top')

comment = Comment("Generated for pystl")