cape.xmlfile: Extended interface to XML files

This module provides the class XMLFile, which extends slightly the built-in class xml.etree.ElmentTree. Compared to the standard library class, XMLFile has a more top-level interface.

Specifically, it is possible to find and/or edit properties of subelements that are arbitrarily deep within the file using methods for the top-level class. This is convenient (for example) for CFD solvers using XML files as their input because it eases the process of changing minor settings (for example the angle of attack) without searching through multiple levels of elements and subelements.

class cape.xmlfile.XMLFile(arg0=None, **kw)

Interface to XML files

Call:
>>> xml = XMLFile(fxml)
>>> xml = XMLFile(xml1)
>>> xml = XMLFile(et)
>>> xml = XMLFile(e)
>>> xml = XMLFile(txt)
>>> xml = XMLFile()
Inputs:
fxml: str

Name of an XML file

et: xml.etree.ElementTree.ElementTree

An XML element tree

e: xml.etree.ElementTree.Element

An XML root element

txt: str

XML text to parse directly

xml1: XMLFile

Another instance

Outputs:
xml: XMLFile

Instance of XML file interface

Attributes:
xml.tree: xml.etree.ElementTree.ElementTree

An XML element tree interface to contents

xml.root: xml.etree.ElementTree.Element

The root element of the XML element tree

xml.fname: None | str

Name of file read or default file name to write

Versions:
  • 2021-10-06 @ddalle: Version 0.0: Started

  • 2021-10-08 @ddalle: Version 1.0

  • 2021-10-18 @ddalle: Version 1.1; text2val()

find(tag, attrib=None, text=None, **kw)

Find an element using full path and expanded search criteria

Call:
>>> elem = xml.find(tag, attrib=None, **kw)
>>> elem = xml.find(tags, attrib=None, **kw)
Examples:

Find the first element called InputList that’s a direct child of the root element:

>>> elem = xml.find("InputList")

Using the following example XML text:

<JobXML>
  <InputList>
    <Input name="Alpha">4.0</Input>
    <Input name="Beta">1.0</Input>
  </InputList>
</JobXML>

find the Input element with attribute name="Alpha":

>>> xml.find("InputList.Input", attrib={"name": "Alpha"})

or, alternatively:

>>> xml.find(["InputList","Input"], attrib={"name":"Alpha"})
Inputs:
xml: XMLFile

XML file interface

tag: str

Subelement tag, using '.' to separate levels

tags: list[str]

Path of tags to sought elem

attrib: {None} | dict

Requirements to match for elem.attrib

attribs: {None} | list[attrib]

Target attrib for each level of tags

text: {None} | str

Target elem.text, ignoring head/tail white space

tail: {None} | str

Target elem.tail, ignoring head/tail white space

exacttext: {None} | str

Target elem.text, exact match

exacttail: {None} | str

Target elem.tail, exact match

Outputs:
elem: Element

Element matching all criteria

Versions:
  • 2021-10-07 @ddalle: Version 1.0

find_iter(tag=None, attrib=None, text=None, **kw)

Find an element at any level using various search criteria

Call:
>>> elem = xml.find_iter(tag, attrib=None, text=None, **kw)
Inputs:
xml: XMLFile

XML file interface

tag: {None} | str

Name of child element to match

attrib: {None} | dict

Dictionary of attributes to match

text: {None} | str

Element text to match, ignoring head/tail

tail: {None} | str

Post-element text to match, ignoring head/tail

exacttext: {None} | str

Element text to match exactly

exacttail: {None} | str

Post-element text to match exactly

finditer: True | {False}

Option to search all levels, not just immediate children

Outputs:
elem: xml.etree.ElementTree.Element

An XML element matching all criteria above

Versions:
  • 2021-10-07 @ddalle: Version 1.0

find_trail(tag, attrib=None, text=None, **kw)

Find an element using full path and expanded search criteria

Call:
>>> elems = xml.find_trail(tag, attrib=None, **kw)
>>> elems = xml.find_trail(tags, attrib=None, **kw)
Inputs:
xml: XMLFile

XML file interface

tag: str

Subelement tag, using '.' to separate levels

tags: list[str]

Path of tags to sought elem

attrib: {None} | dict

Requirements to match for elem.attrib

attribs: {None} | list[attrib]

Target attrib for each level of tags

text: {None} | str

Target elem.text, ignoring head/tail white space

tail: {None} | str

Target elem.tail, ignoring head/tail white space

exacttext: {None} | str

Target elem.text, exact match

exacttail: {None} | str

Target elem.tail, exact match

Outputs:
elems: list[Element]

Path of elements leading up to requested tag

Versions:
  • 2021-10-07 @ddalle: Version 1.0

findall_iter(tag=None, attrib=None, text=None, **kw)

Find all elements at any level using various search criteria

Call:
>>> elems = xml.findall_iter(tag, attrib=None, **kw)
Inputs:
xml: XMLFile

XML file interface

tag: {None} | str

Name of child element to match

attrib: {None} | dict

Dictionary of attributes to match

text: {None} | str

Element text to match, ignoring head/tail

tail: {None} | str

Post-element text to match, ignoring head/tail

exacttext: {None} | str

Element text to match exactly

exacttail: {None} | str

Post-element text to match exactly

finditer: True | {False}

Option to search all levels, not just immediate children

Outputs:
elems: list[Element]

All XML elements matching all criteria above

Versions:
  • 2021-10-07 @ddalle: Version 1.0

pop(tag, attrib=None, text=None, **kw)

Remove an element if found

Call:
>>> elem = xml.pop(tag, attrib=None, **kw)
>>> elem = xml.pop(tags, attrib=None, **kw)
Inputs:
xml: XMLFile

XML file interface

tag: str

Subelement tag, using '.' to separate levels

tags: list[str]

Path of tags to sought elem

attrib: {None} | dict

Requirements to match for elem.attrib

attribs: {None} | list[attrib]

Target attrib for each level of tags

text: {None} | str

Target elem.text for searching

tail: {None} | str

Target elem.tail for searching

exacttext: {None} | str

Target elem.text, exact match

exacttail: {None} | str

Target elem.tail, exact match

Outputs:
elem: None | Element

Element matching all criteria, if present

Versions:
  • 2021-10-08 @ddalle: Version 1.0

remove(tag, attrib=None, text=None, **kw)

Remove an element; raise exception if not found

Call:
>>> xml.remove(tag, attrib=None, **kw)
>>> xml.remove(tags, attrib=None, **kw)
Inputs:
xml: XMLFile

XML file interface

tag: str

Subelement tag, using '.' to separate levels

tags: list[str]

Path of tags to sought elem

attrib: {None} | dict

Requirements to match for elem.attrib

attribs: {None} | list[attrib]

Target attrib for each level of tags

text: {None} | str

Target elem.text for searching

tail: {None} | str

Target elem.tail for searching

exacttext: {None} | str

Target elem.text, exact match

exacttail: {None} | str

Target elem.tail, exact match

Versions:
  • 2021-10-08 @ddalle: Version 1.0

set_elem(tag, newtext=None, attrib=None, **kw)

Edit or insert an element

Call:
>>> xml.set_elem(tag, newtext, attrib=None, **kw)
>>> xml.set_elem(tags, newtext, attrib=None, **kw)
Examples:

Using the following example XML text:

<JobXML>
  <InputList>
    <Input name="Alpha">4.0</Input>
    <Input name="Beta">1.0</Input>
  </InputList>
</JobXML>

Suppose we want to find the Input element with attribute name="Alpha" and change the value (text to 3.0):

xml.set_elem(
    "InputList.Input", 3.0, attrib={"name": "Alpha"})

Suppose we want to add a condition for "Mach" at 1.5:

xml.set_elem(
    "InputList.Input", 1.5, attrib={"name": "Mach"})

Suppose we want to change "Alpha" to "alpha":

xml.set_elem(
    "InputList.Input", attrib={"name": "Alpha"},
    newattrib={"name": "alpha"})
Inputs:
xml: XMLFile

XML file interface

tag: str

Subelement tag, using '.' to separate levels

tags: list[str]

Path of tags to sought elem

newtext: {None} | str

The final text to set in new/edited element

attrib: {None} | dict

Requirements to match for elem.attrib

attribs: {None} | list[attrib]

Target attrib for each level of tags

insert: {True} | False

Option to insert new element(s) if not found

indent: {2} | int >= 0

Number of spaces in an indent

tab: {indent * " "} | str

Override indent with a specific string

text: {None} | str

Target elem.text for searching

tail: {None} | str

Target elem.tail for searching

exacttext: {None} | str

Target elem.text, exact match

exacttail: {None} | str

Target elem.tail, exact match

newattrib: {None} | dict

New attributes to set in found element

newtail: {None} | str

Specific final tail text for found dlement

updateattrib: {None} | dict

Attributes to update without resetting elem.attrib

Versions:
  • 2021-10-08 @ddalle: Version 1.0

text2val(txt)

Convert XML text to Python value

Call:
>>> v = xml.text2val(txt)
Inputs:
xml: XMLFile

XML file interface

txt: str

Text to convert

Outputs:
v: None | bool | int | float | str

Converted value

Versions:
  • 2021-10-18 @ddalle: Version 1.0

val2text(v)

Convert Python value to XML text

Call:
>>> txt = xml.val2text(v)
Inputs:
xml: XMLFile

XML file interface

v: any

Python value to convert

Outputs:
txt: str

Converted text

Versions:
  • 2021-10-18 @ddalle: Version 1.0

write(fname=None)

Write a file

Call:
>>> xml.write(fname=None)
Inputs:
xml: XMLFile

XML file interface

fname: {None} | str

Name of file to write

Versions:
  • 2021-10-07 @ddalle: Version 1.0

cape.xmlfile.find_elem(e, tag=None, attrib=None, text=None, **kw)

Find a [direct] child of e using full search criteria

Call:
>>> elem = find_elem(e, tag, attrib=None, text=None, **kw)
Inputs:
e: xml.etree.ElementTree.Element

An XML element using standard library interface

tag: {None} | str

Name of child element to match

attrib: {None} | dict

Dictionary of attributes to match

text: {None} | str

Element text to match, ignoring head/tail

tail: {None} | str

Post-element text to match, ignoring head/tail

exacttext: {None} | str

Element text to match exactly

exacttail: {None} | str

Post-element text to match exactly

finditer: True | {False}

Option to search all levels, not just immediate children

Outputs:
elem: xml.etree.ElementTree.Element

An XML element matching all criteria above

Versions:
  • 2021-10-07 @ddalle: Version 1.0

cape.xmlfile.findall_elem(e, tag=None, attrib=None, text=None, **kw)

Find all [direct] children of e using full search criteria

Call:
>>> elems = findall_elem(e, tag, attrib=None, text=None, **kw)
Inputs:
e: xml.etree.ElementTree.Element

An XML element using standard library interface

tag: {None} | str

Name of child element to match

attrib: {None} | dict

Dictionary of attributes to match

text: {None} | str

Element text to match, ignoring head/tail

tail: {None} | str

Post-element text to match, ignoring head/tail

exacttext: {None} | str

Element text to match exactly

exacttail: {None} | str

Post-element text to match exactly

finditer: True | {False}

Option to search all levels, not just immediate children

Outputs:
elems: list[Element]

All XML elements matching all criteria above

Versions:
  • 2021-10-07 @ddalle: Version 1.0

cape.xmlfile.toelement(tag, attrib=None, text=None, tail=None)

Create a new element from basic properties

Call:
>>> e = toelement(tag, attrib=None, text=None, tail=None)
Inputs:
tag: str

Name of the XML element

attrib: {None} | dict

Attributes for the XML element

text: {None} | str

Text for the interior of the element

tail: {None} | str

Text after the element

Outputs:
e: Element

New XML element

Versions:
  • 2021-10-07 @ddalle: Version 1.0