-
Notifications
You must be signed in to change notification settings - Fork 64
ReplaceOneTextToAnother
yacc143 edited this page Mar 2, 2022
·
6 revisions
!!! This example not work properly in some cases. Please give correct way for this task.
This does not work correctly, as not all texts are in Span elements. Some texts actually happen to be stuck directly, say into text.P elements. This can probably happen with other elements too, e.g. tables. All text is actually stored in odf.element.Text instances, which oops, are not odf.element.Element derived, hence, cannot be looked up with doc.getElementsByType.
That's why this code will not always work, and why the overall framework offers little introspection into existing documents if one is not willing to write some additional code.
from odf import opendocument, text, teletype
doc = opendocument.load('test.odt')
for item in doc.getElementsByType(text.Span):
s = teletype.extractText(item)
if s.find('Replace this') != -1:
s = s.replace('Replace this', 'to this')
new_item = text.Span()
new_item.setAttribute('stylename', item.getAttribute('stylename'))
new_item.addText(s)
item.parentNode.insertBefore(new_item, item)
item.parentNode.removeChild(item)
doc.save('result.odt')
So what do we need?
We need to iterate over the XML tree that the SaX parser build on our own:
def saxiter(node : Element) -> Iterator[Element]:
"""return an interator over all elements reachable from node: later siblings and recursively all children."""
while node:
yield node
if node.hasChildNodes():
yield from saxiter(node.firstChild)
node = node.nextSibling
def edittextElements(doc : OpenDocument, pattern : list[str]) -> Generator[tuple[str, str], str, None]:
"""go over all elements, and look for the text that contains the given."""
for elem in saxiter(doc.topnode):
if elem.__class__ is Text:
for pat in pattern:
if pat in str(elem):
elem.data = yield (pat, elem.data)