Inhalt eines Strings als Funktion ausführen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Rigoletto
User
Beiträge: 28
Registriert: Freitag 14. Februar 2014, 21:05

@jerch: Die inkex.py (schnittstelle) hab ich mir schon angeschaut. Leider nur Python 2.x, keine interaction mit den erstellen svg-Elementen, nur ein File-Handle einer temp. svg-Datei die man dann berarbeiten kann. Mit Python 2.x will ich nichts mehr machen, ggf. mach ich noch ein Wrapper der mit das File in Python 3.x weiterleitet aber das war es auch schon. Die Gui die inkscape momentan bietet ist auch nicht so toll, für meinen Dialog nehm ich da das tkinter von Python 3.x.

@sirus: Wenn ich eine Template-Engine nehme kann ich aber die Vorlage nicht mehr in inkscape veränderen, das würde bei vielen veränderungen das Template zerstören. Jedenfalls seh ich da keinen Weg das zu umgehen.
Ja, wenn ich den Platzhalter direkt in ein Attribut eintrage stimmt die Anzeige nicht mehr. Wenn ich könnte würde ich ja einfach ein Button mache wie in Word, der umschalten zwischen Vorschau mit Daten und Platzhalter. Aber leider bietet das die Schnittstelle nicht. Wenn ich einen Auftruf mache ändert er direkt das Template und dann kann ich nicht mehr auf Ansicht mit Platzhalter zurück. Jedenfalls nicht so einfach.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@Rigoletto: ja, genau richtig erkannt. Wenn man Platzhalter einbaut, funktioniert das svg nicht mehr und wenn man das Template ändert, kann man damit auch die Platzhalter kaputt machen. Das ist aber unabhängig von der verwendeten Template-Engine, ob eine fertige, oder Deine zusammengebaute. Nur wenn man IDs nimmt und die IDs außerhalb des Templates (in Python) mit entsprechenden Funktionen hinterlegt, denke ich, ist ein Hybrid-Betrieb (Ändern des Templates und Ausfüllen) möglich.
Rigoletto
User
Beiträge: 28
Registriert: Freitag 14. Februar 2014, 21:05

@Sirus: Das ich so nicht in der Lage bin eine 100% benutzerfreundliche Lösung zu bieten war mir zu Beginn schon klar. Aber wenn ich auf Inkscape als Editor setze und mit Python die Platzhalter austausche habe ich zumindest eine Lösung die das bearbeiten des Templates relativ einfach macht. Das Result sehe ich dann sehe ich dann nach generieren der Etiketten.

Tausche ich aber meine Platzhalter gegen die IDs aus muss ich die IDs an die Daten zuweisen was ich für unpraktisch halte.
Aber jetzt wo du es sagst, umgekehrt wäre es eine praktikable Lösung. Wenn der Benutzer einfach ein neues spezielles Attribut hinzufügt das nur für das externe Python-Programm ist.

oldata="text:Hier kommt mein {Text}."
Würde den Text des Elementes austauschen.

oldata="style:fill:{color}"
Ersetzt einen Teil vom Attribut oder fügt es ein.

oldata="text:Noch ein {Text}.;xlink:href{picturefile}"
Mischen sollte auch kein Problem sein.

Damit könnte ich leben. Man könnte die Syntax auch vereinfachen und statt sowas wie xlink:href einfach bild:{picturefile} nehmen.
Sind damit jetzt alle zufrieden und können wir zur meiner eigentlichen Frage zurückommen :)
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@Rigoletto: Inkscape parst die ihm bekannten Attribute und wirft alle Platzhalter raus. Man braucht also Platzhalter-Attribute damit man weiterhin mit Inkscape arbeiten kann.

Was ist denn nun Deine eigentliche Frage?
Rigoletto
User
Beiträge: 28
Registriert: Freitag 14. Februar 2014, 21:05

Sirius3 hat geschrieben:@Rigoletto: Inkscape parst die ihm bekannten Attribute und wirft alle Platzhalter raus. Man braucht also Platzhalter-Attribute damit man weiterhin mit Inkscape arbeiten kann.

Was ist denn nun Deine eigentliche Frage?
Nicht ganz, wenn man als Attribut fill:{color} nimmt anstatt style:fill:#ffff00 geht es. Er wandelt es dann aber um wenn er es gültig is nach dem ausstauschen.

Kann ich einen String z. B. "print('hier bin ich') "temporär in eine Funktion umwandeln. Momentan fällt mir nur ein als temp.py speichern und ausführen.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@Rigoletto: warum schreibst Du nicht einfach

Code: Alles auswählen

print(text)
und speicherst in Deinem String nur "hier bin ich"?
Rigoletto
User
Beiträge: 28
Registriert: Freitag 14. Februar 2014, 21:05

@Sirus: War jetzt nur ein Beispiel, den mehrzeiligen Code

Code: Alles auswählen

def foo(element):
    #hole subelement(e) und verarbiete es
würde ich ein einem <g> Tag speichern der dann die enthaltnen Elemente bearbeiten soll.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@Rigoletto: so kommen wir nicht weiter, weil ich immer noch nicht weiß, was Du eigentlich konkret willst. Kannst Du mal ein Beispiel svg-Template erzeugen und das gewünschte Ergebnis dazu. Das macht glaube ich die Sache viel klarer.
Rigoletto
User
Beiträge: 28
Registriert: Freitag 14. Februar 2014, 21:05

Hier als Beispiel ein Adress-Etikett:

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="7cm"
   height="4cm"
   viewBox="0 0 248.0315 141.73228"
   id="svg2"
   version="1.1"
   inkscape:version="0.91 r13725"
   sodipodi:docname="6zeilig.svg">
  <defs
     id="defs4" />
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="4.7211746"
     inkscape:cx="124.01575"
     inkscape:cy="79.950773"
     inkscape:document-units="cm"
     inkscape:current-layer="svg2"
     showgrid="false"
     units="cm"
     inkscape:window-width="1920"
     inkscape:window-height="1028"
     inkscape:window-x="-8"
     inkscape:window-y="-8"
     inkscape:window-maximized="1" />
  <metadata
     id="metadata7">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Ebene 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(0,-910.62998)" />
  <g
     id="g4151"
     transform="matrix(0.95434197,0,0,0.95434197,0.5857467,5.2415298)"><text
   sodipodi:linespacing="125%"
   id="text4136"
   y="21.725454"
   x="7.0866141"
   style="font-style:normal;font-weight:normal;font-size:17.93287468px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
   xml:space="preserve"><tspan
     y="21.725454"
     x="7.0866141"
     id="tspan4138"
     sodipodi:role="line"
     oldata="{Name}">Zeile1</tspan><tspan
     id="tspan4140"
     y="44.141548"
     x="7.0866141"
     sodipodi:role="line"
     oldata="{Name2}">Zeile2</tspan><tspan
     id="tspan4142"
     y="66.55764"
     x="7.0866141"
     sodipodi:role="line"
     oldata="{Strasse}">Zeile3</tspan><tspan
     id="tspan4144"
     y="88.973732"
     x="7.0866141"
     sodipodi:role="line"
     oldata="{PLZ} {Ort}">Zeile4</tspan><tspan
     id="tspan4146"
     y="111.38983"
     x="7.0866141"
     sodipodi:role="line"
     oldata="{Land}">Zeile5</tspan></text>


		 def adr_format(element):
			# eliminiere Leerzeilen
			# gebe Land nur aus wenn <>'Deutschland'
			pass
  </g>
</svg>

Wenn die Daten nun folgende wären:

Name:Donald Duck
Name2:
Strasse:Entengasse 1
PLZ:12345
Ort:Entenhausen
Land:Comicland

soll die Funktion die im Text der Gruppe steht ausgeführt werden auf das übergebene Element. Was in diesen Fall die Gruppe mit der id=g4151 wäre.
Damit dann als Ergebniss ein Etikett ohne Leerzeilen rauskommt:

Donald Duck
Entengasse 1
12345 Entenhausen
Comicland
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@Rigoletto: Was ist denn jetzt der Vorteil den Ersetzungstext in ein Attribut zu stecken? Ein <tspan ...>{Name}</tspan> ist doch viel logischer und man sieht gleich, dass hier ein Text ersetzt werden soll.

Wie stellst Du Dir die Funktion vor, die Du da in das xml hineinschreibst? Die müßte ja das svg in nicht-trivialer Weise verändern.

Dagegen hier nur mal als Beispiel mit jinja2 umgesetzt:

Code: Alles auswählen

from jinja2 import Environment, PackageLoader
env = Environment(loader=PackageLoader('__main__', '.'))
template = env.get_template('template.svg')
with open("output.svg", "w") as out:
    out.write(template.render({
        "Name":"Donald Duck",
        "Name2":"",
        "Strasse":"Entengasse 1",
        "PLZ":"12345",
        "Ort":"Entenhausen",
        "Land":"Deutschland",
    }))
mit passender svg-Datei

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="7cm"
   height="4cm"
   viewBox="0 0 248.0315 141.73228"
   id="svg2"
   version="1.1">
  <defs
     id="defs4" />
  <g
     inkscape:label="Ebene 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(0,-910.62998)" />
  <g
     id="g4151"
     transform="matrix(0.95434197,0,0,0.95434197,0.5857467,5.2415298)"><text
   sodipodi:linespacing="125%"
   id="text4136"
   y="21.725454"
   x="7.0866141"
   style="font-style:normal;font-weight:normal;font-size:17.93287468px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
   xml:space="preserve"><tspan
     y="21.725454"
     x="7.0866141"
     id="tspan4138"
     sodipodi:role="line">{%if Name2 %}{{Name}}{%endif%}</tspan><tspan
     id="tspan4140"
     y="44.141548"
     x="7.0866141"
     sodipodi:role="line">{%if Name2 %}{{Name2}}{%else%}{{Name}}{%endif%}</tspan><tspan
     id="tspan4142"
     y="66.55764"
     x="7.0866141"
     sodipodi:role="line">{{Strasse}}</tspan><tspan
     id="tspan4144"
     y="88.973732"
     x="7.0866141"
     sodipodi:role="line">{{PLZ}} {{Ort}}</tspan><tspan
     id="tspan4146"
     y="111.38983"
     x="7.0866141"
     sodipodi:role="line">{%if Land != "Deutschland" %}{{Land}}{%endif%}</tspan></text>
  </g>
</svg>
Rigoletto
User
Beiträge: 28
Registriert: Freitag 14. Februar 2014, 21:05

Sirius3 hat geschrieben:@Rigoletto: Was ist denn jetzt der Vorteil den Ersetzungstext in ein Attribut zu stecken? Ein <tspan ...>{Name}</tspan> ist doch viel logischer und man sieht gleich, dass hier ein Text ersetzt werden soll.

Wie stellst Du Dir die Funktion vor, die Du da in das xml hineinschreibst? Die müßte ja das svg in nicht-trivialer Weise verändern.
....
@Sirus: Du hast mich doch auf die Idee gebracht die Ersetzung in ein Attribut zu stecken :), der Vorteil ich kann eine Vorschau an und aussschalten in dem ich das Attribut oder das geparste Attribut in den Text kopiere. Und ob ich jetzt jinja nehme oder die paar Funktionen die ich brauche selber schreibe wie ich es erst geplant hatte, beide haben einen Platzhalter direkt im Text.

Nein, ganz einfach ist die Funktion sicher nicht aber auch kein riesiges Problem. Wahrscheinlich kann ich das Problem auch in 2, 3 kleine generelle Funktionen aufsplitten die dann nur aufgerufen werden.

@alle Beitragsposter: Ich finde es ja toll das ihr mir hier alle Tipps gebt und auf mögliche Probleme hinweist und Lösungsvorschläge macht, und sogar richtig Zeit opfert und mir fertigen Code hier liefert.
Sirius hat sich sogar die Mühe gemacht Inkscape zu installieren und selber mal in die Software zu schauen, wenn ich mich nicht irre, echt top.
Aber ich fühl mich echt ein bißchen verarscht, das ich auf die Frage wie ich den Inhalt eines String als Funktion ausführe, egal woher er nun kommt aus einer xml, einer txt, einer jinja template, noch keine Antwort habe.
BlackJack

@Rigoletto: Weil das in der Regel nicht das ist was man machen möchte. Zum einen weil's Sicherheitslöcher reisst und weil es sehr oft dazu verwendet wird nicht den normalen Weg über die angebotenen Sprachmittel zu gehen, sondern sich aus Unkenntnis oder Faulheit irgend eine krude ”Lösung” zusammenzuhacken. Zudem treten auch Schwierigkeiten mit der Einbettung von Python-Quelltext in andere Datenformate auf die Leerzeichen/Einrückung nicht so behandeln wie Python das benötigt.
Antworten