-
Notifications
You must be signed in to change notification settings - Fork 64
ReplaceOneTextToAnother
-Smooth-E- edited this page Feb 15, 2023
·
6 revisions
⚠ Warning
This example does 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
document = opendocument.load('test.odt')
for element in document.getElementsByType(text.Span):
extracted_text = teletype.extractText(element)
if extracted_text.find('Replace this') != -1:
extracted_text = extracted_text.replace('Replace this', 'to this')
new_element = text.Span()
new_element.setAttribute('stylename', element.getAttribute('stylename'))
new_element.addText(extracted_text)
element.parentNode.insertBefore(new_element, element)
element.parentNode.removeChild(element)
document.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]:
"""Goes 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)