String Interpolation in ElementTree implementieren

Hallo, ich will erreichen, dass man in XML Ersetzungen einbetten kann, also: <root filesystem="{filesystem}"> {files} </root> ich habe ein Dictionary repl = {"filesystem" : "btrfs", "files" : "whatever"} und würde das beim parsen des XML einfach mitgeben und bekomme dann die Strings schon fertig eingesetzt zurück. Ersetzt werden sollen Attribute und Text. Hier fängt das Problem an. Als XML-API benutze ich ElementTree. Das einfachste wäre wohl, wenn der ElementTree benutzende Code sich selber drum kümmert: str = interpolate(node.attrib["filesystem"], repl). Oder halt einfach direkt .format aufruft. Mir wäre es aber am liebsten, wenn ich das weitgehend transparent einbinden könnte. Wenn ich nun von xml.etree.ElementTree.ElementTree ableite und die Methoden text und attrib überschreibe, ok... Nur müsste ich wohl auch sämtliche Funktionen modifizieren, die ElementTrees zurückgeben (damit sie meine Kindklasse zurückgeben) und das wäre dann wohl doch recht viel Aufwand. Wie macht man sowas am geschicktesten? Danke, Florian

Ich würde die einfach eine templating engine wie zb genshi empfehlen. Die kann das und kümmert sich um all die Details. Diez Am 23.09.2012 um 12:23 schrieb Florian Lindner <mailinglists@xgm.de>:
Hallo,
ich will erreichen, dass man in XML Ersetzungen einbetten kann, also:
<root filesystem="{filesystem}"> {files} </root>
ich habe ein Dictionary repl = {"filesystem" : "btrfs", "files" : "whatever"} und würde das beim parsen des XML einfach mitgeben und bekomme dann die Strings schon fertig eingesetzt zurück. Ersetzt werden sollen Attribute und Text.
Hier fängt das Problem an. Als XML-API benutze ich ElementTree.
Das einfachste wäre wohl, wenn der ElementTree benutzende Code sich selber drum kümmert: str = interpolate(node.attrib["filesystem"], repl). Oder halt einfach direkt .format aufruft.
Mir wäre es aber am liebsten, wenn ich das weitgehend transparent einbinden könnte. Wenn ich nun von xml.etree.ElementTree.ElementTree ableite und die Methoden text und attrib überschreibe, ok... Nur müsste ich wohl auch sämtliche Funktionen modifizieren, die ElementTrees zurückgeben (damit sie meine Kindklasse zurückgeben) und das wäre dann wohl doch recht viel Aufwand.
Wie macht man sowas am geschicktesten?
Danke,
Florian _______________________________________________ python-de maillist - python-de@python.org http://mail.python.org/mailman/listinfo/python-de

Am Sonntag, 23. September 2012, 13:58:05 schrieb Diez B. Roggisch:
Ich würde die einfach eine templating engine wie zb genshi empfehlen. Die kann das und kümmert sich um all die Details.
Hallo, ich habe mir Genshi eben mal angeschaut und für meinen Anwendungszweck ist das Overkill. Eine Möglichkeit in Python der ElementTree Klasse eine eigenes, von Element abgeleitete Klasse unterzuschieben gibt es nicht? Wie würde man sonst an das Problem rangehen: Ich will das Verhalten einer Klasse modfizieren, die selten direkt instanziert wird, sondern idR von Factory-Funktionen zurückgegben wird. Grüße, Florian
Am 23.09.2012 um 12:23 schrieb Florian Lindner <mailinglists@xgm.de>:
Hallo,
ich will erreichen, dass man in XML Ersetzungen einbetten kann, also:
<root filesystem="{filesystem}"> {files} </root>
ich habe ein Dictionary repl = {"filesystem" : "btrfs", "files" : "whatever"} und würde das beim parsen des XML einfach mitgeben und bekomme dann die Strings schon fertig eingesetzt zurück. Ersetzt werden sollen Attribute und Text.
Hier fängt das Problem an. Als XML-API benutze ich ElementTree.
Das einfachste wäre wohl, wenn der ElementTree benutzende Code sich selber drum kümmert: str = interpolate(node.attrib["filesystem"], repl). Oder halt einfach direkt .format aufruft.
Mir wäre es aber am liebsten, wenn ich das weitgehend transparent einbinden könnte. Wenn ich nun von xml.etree.ElementTree.ElementTree ableite und die Methoden text und attrib überschreibe, ok... Nur müsste ich wohl auch sämtliche Funktionen modifizieren, die ElementTrees zurückgeben (damit sie meine Kindklasse zurückgeben) und das wäre dann wohl doch recht viel Aufwand.
Wie macht man sowas am geschicktesten?

On 9/24/12 11:05 AM, "Florian Lindner" <mailinglists@xgm.de> wrote:
Am Sonntag, 23. September 2012, 13:58:05 schrieb Diez B. Roggisch:
Ich würde die einfach eine templating engine wie zb genshi empfehlen. Die kann das und kümmert sich um all die Details.
Hallo,
ich habe mir Genshi eben mal angeschaut und für meinen Anwendungszweck ist das Overkill.
Wieso? Das Interface ist so dünn wie möglich, die erweiterten Funktionalitaeten wie looping/if-else musst du ja nicht nutzen. """ from genshi.template import MarkupTemplate, NewTextTemplate tmpl = MarkupTemplate('''<root xmlns:py="http://genshi.edgewall.org/" filesystem="${filesystem}"> ${files} </root>''') print tmpl.generate(filesystem="foo", files=[1, 2, 3]) """ Ich finde viel dünner geht's nicht mehr
Eine Möglichkeit in Python der ElementTree Klasse eine eigenes, von Element abgeleitete Klasse unterzuschieben gibt es nicht?
Nicht per se, siehe unten.
Wie würde man sonst an das Problem rangehen: Ich will das Verhalten einer Klasse modfizieren, die selten direkt instanziert wird, sondern idR von Factory-Funktionen zurückgegben wird.
Wenn der Autor das nicht vorgesehen hat, dann geht sowas nicht so ohne weiteres. UU kannst du monkey-patchen (was auch schon blöde genug ist), aber je nach dem wie ET geschrieben ist bedeutet das letztendlich, eine eigene Version davon bereitzustellen. Das faende *ich* dann Overkill. Diez

Florian Lindner, 23.09.2012 12:23:
ich will erreichen, dass man in XML Ersetzungen einbetten kann, also:
<root filesystem="{filesystem}"> {files} </root>
ich habe ein Dictionary repl = {"filesystem" : "btrfs", "files" : "whatever"} und würde das beim parsen des XML einfach mitgeben und bekomme dann die Strings schon fertig eingesetzt zurück. Ersetzt werden sollen Attribute und Text.
Hier fängt das Problem an. Als XML-API benutze ich ElementTree.
Das einfachste wäre wohl, wenn der ElementTree benutzende Code sich selber drum kümmert: str = interpolate(node.attrib["filesystem"], repl). Oder halt einfach direkt .format aufruft.
Mir wäre es aber am liebsten, wenn ich das weitgehend transparent einbinden könnte. Wenn ich nun von xml.etree.ElementTree.ElementTree ableite und die Methoden text und attrib überschreibe, ok... Nur müsste ich wohl auch sämtliche Funktionen modifizieren, die ElementTrees zurückgeben (damit sie meine Kindklasse zurückgeben) und das wäre dann wohl doch recht viel Aufwand.
Da möchte ich von abraten. Mach deine Ersetzung explizit durch einen Funktionsaufruf.
Wie macht man sowas am geschicktesten?
Mach das ganz am Ende der Verarbeitung, direkt vor dem Rausschreiben. Iterier über alle Elemente und mach dabei deine Ersetzungen, auch im "attrib" dict. Das sind nur ein paar Zeilen Code und du bist vollständig unabhängig davon, welche ET-Implementierung benutzt wird (ET, cET, lxml) oder wie sich diese Implementierung intern weiter entwickelt. Stefan

On 25.09.12 07:30, Stefan Behnel wrote:
Florian Lindner, 23.09.2012 12:23:
ich will erreichen, dass man in XML Ersetzungen einbetten kann, also:
<root filesystem="{filesystem}"> {files} </root>
ich habe ein Dictionary repl = {"filesystem" : "btrfs", "files" : "whatever"} und würde das beim parsen des XML einfach mitgeben und bekomme dann die Strings schon fertig eingesetzt zurück. Ersetzt werden sollen Attribute und Text.
Hier fängt das Problem an. Als XML-API benutze ich ElementTree.
Das einfachste wäre wohl, wenn der ElementTree benutzende Code sich selber drum kümmert: str = interpolate(node.attrib["filesystem"], repl). Oder halt einfach direkt .format aufruft.
Mir wäre es aber am liebsten, wenn ich das weitgehend transparent einbinden könnte. Wenn ich nun von xml.etree.ElementTree.ElementTree ableite und die Methoden text und attrib überschreibe, ok... Nur müsste ich wohl auch sämtliche Funktionen modifizieren, die ElementTrees zurückgeben (damit sie meine Kindklasse zurückgeben) und das wäre dann wohl doch recht viel Aufwand.
Da möchte ich von abraten. Mach deine Ersetzung explizit durch einen Funktionsaufruf.
Wie macht man sowas am geschicktesten?
Mach das ganz am Ende der Verarbeitung, direkt vor dem Rausschreiben. Iterier über alle Elemente und mach dabei deine Ersetzungen, auch im "attrib" dict. Das sind nur ein paar Zeilen Code und du bist vollständig unabhängig davon, welche ET-Implementierung benutzt wird (ET, cET, lxml) oder wie sich diese Implementierung intern weiter entwickelt.
Alternativ kannst Du das natürlich dann machen, *nachdem* Du aus dem ElementTree einen XML-String erzeugt hast. Servus, Walter

Mach das ganz am Ende der Verarbeitung, direkt vor dem Rausschreiben. Iterier über alle Elemente und mach dabei deine Ersetzungen, auch im "attrib" dict. Das sind nur ein paar Zeilen Code und du bist vollständig unabhängig davon, welche ET-Implementierung benutzt wird (ET, cET, lxml) oder wie sich diese Implementierung intern weiter entwickelt.
Alternativ kannst Du das natürlich dann machen, *nachdem* Du aus dem ElementTree einen XML-String erzeugt hast.
Jepp, und sich dann all die Dinge einfangen, die man durch die Behandlung von XML als Strings bekommt: nicht korrekt ausgezeichnete Attribut-Werte, & und < und andere Zeichen, die ebenfalls nicht sonderbehandelt wurden, encoding Fehler usw. Also besser nicht :) Diez

Am Sonntag, 23. September 2012, 12:23:34 schrieb Florian Lindner:
Hallo,
ich will erreichen, dass man in XML Ersetzungen einbetten kann, also:
<root filesystem="{filesystem}"> {files} </root>
ich habe ein Dictionary repl = {"filesystem" : "btrfs", "files" : "whatever"} und würde das beim parsen des XML einfach mitgeben und bekomme dann die Strings schon fertig eingesetzt zurück. Ersetzt werden sollen Attribute und Text.
Hier fängt das Problem an. Als XML-API benutze ich ElementTree.
Das einfachste wäre wohl, wenn der ElementTree benutzende Code sich selber drum kümmert: str = interpolate(node.attrib["filesystem"], repl). Oder halt einfach direkt .format aufruft.
Mir wäre es aber am liebsten, wenn ich das weitgehend transparent einbinden könnte. Wenn ich nun von xml.etree.ElementTree.ElementTree ableite und die Methoden text und attrib überschreibe, ok... Nur müsste ich wohl auch sämtliche Funktionen modifizieren, die ElementTrees zurückgeben (damit sie meine Kindklasse zurückgeben) und das wäre dann wohl doch recht viel Aufwand.
Soo, nochmal eine kleine Rückmeldung, wie ich es nun gemacht habe. Ein Worker weiß selber, ob er Subworker hat (die den Kontext und damit die Ersetzungstabelle verändern können) oder nicht. Deshalb habe ich der Basisklasse aller Worker diese Funktion hinzugefügt: def do_string_interpolation(self, recurse=True): """ Replace all strings like {U} with the value from the context dictionary if it exists. Workers that can have subworkers should not recurse. """ if recurse: selection = ".//" else: selection = "." for n in self.config.findall(selection): try: n.text = n.text.format(**self.context) except (AttributeError, KeyError): pass for a in n.attrib: try: n.attrib[a] = n.attrib[a].format(**self.context) except KeyError: passttrib[a].format(**self.context) except KeyError: pass Diese wird im Konstruktur aufgerufen. Damit Worker, die nicht rekursiv ersetzen wollen dies können: class BaseWorker(): """ Base Class for all workers. """ def __init__(self, configuration, context, recursive_string_interpolation=True): Diese müssen dann halt __init__ überschreiben und den Konstruktur mit False entsprechend aufrufen. Viele Grüße, Florian
participants (5)
-
Diez B. Roggisch
-
Diez Roggisch
-
Florian Lindner
-
Stefan Behnel
-
Walter Dörwald