NickG
Returning Observer

Search and Replace Skripts für Linkvorlagen

Jump to solution

Hallo,

ich versuche mich aktuell an einem Skript, welches projektweit nach einem Linktemplate suchen, den Inhalt auslesen und bei Bedarf ändern soll.

Konkret geht es um ein Linktemplate, welches die Eingabe von Links in einem CMS_INPUT_TEXT erlaubt.

Diesen Inhalt möchte ich ändern, weil wir aktuell unsere Webseite umstrukturieren. Damit würde den Redakteuren eine Menge Arbeit erspart.

Was ich bisher habe ist das holen der Referenzen des Linktemplates per:

TemplateStoreRoot templateStore = userService.getTemplateStore();

LinkTemplates linkTemplates = templateStore.getLinkTemplates();

LinkTemplate linkTemplate = linkTemplates.getTemplate("link_external");

ReferenceEntry[] references = linkTemplate.getIncomingReferences();

Allerdings bekomme ich da nicht die jeweilige Instanz der Linkvorlage, sondern die des übergeordneten Elementes.

Davon gibt es bei uns allerdings eine Menge. Aktuell habe ich 18 Templates identifiziert, die dieses Linktemplate einbinden können.

Muss ich nun alle 18 Varianten im Skript durchgehen und mich vom übergeordneten Element bis zum gesuchten link Element durcharbeiten, damit ich die Änderung vornehmen kann?

Gibt es einen leichteren Weg, um zum Beispiel direkt alle Instanzen des Linktemplates zu bekommen?

Viele Grüße

Nick

Edit:

Ich habe bereits einen älteren ähnlichen Beitrag gefunden (URLs von Links via Skript modifizieren ). Hier scheint nur der Weg über alle 18 Wege zu iterieren zu funktionieren.

0 Kudos
1 Solution

Accepted Solutions

Hallo Nick,

auf jeden Fall solltest du schon mal das setTemplate weglassen. Und dir fehlt das speichern, sowie das setzen der FormDatas.

Zudem gibt es noch eine Besonderheit - bei mir hat es immer Probleme gemacht, wenn ich den Link aus der LinkNode "wiederverwendet" habe. Ich musste immer einen neuen erstellen und die FormData übertragen. Das könnte dann alles in allem so aussehen:

parentPage.setLock(true, true);

FormData frmData = section.getFormData();

FormField<?> domEditor = frmData.get(language, "st_text");

DomElement domElement = (DomElement) domEditor.get();

DefaultDomNode domRoot = domElement.getRoot();

for (DomNode node : domRoot.getChildren(true)) {

     if (node.getNodeType() == DomNodeType.LINK) {

          LinkDomNode linkNode = (LinkDomNode) node;

          Link link = linkNode.getLink();

          if ("textlinkexternal".equals(link.getTemplate().getUid())) {

               Link newLink = link.getTemplate().createLink(link.getLinkLanguage()); // Neuen Link erzeugen

               FormData linkFormData = link.getFormData();

               FormField<?> refField = linkFormData.get(null, "ref");

               String oldText = (String) refField.get();

               String newText = oldText.replaceAll("e", "a");

               refField.set(newText); // Neuer Wert dem FormField zuweisen

               newLink.setFormData(linkFormData); // Aktualisierte FormData dem Link zuweisen

               linkNode.setLink(newLink); // Link der LinkNode zuweisen

          }

     }

}

domEditor.set(domElement); // Wert im CMS_INPUT_DOM setzen

section.setFormData(frmData); // Aktualisierte FormData der Section zuweisen

parentPage.save();

parentPage.setLock(false, true);

Gruß

Felix

View solution in original post

0 Kudos
8 Replies
felix_reinhold
Returning Responder

Hallo Nick,

Ja, das ist korrekt - du wirst alle Wege abdecken müssen. Ich mache dies in der Regel so, dass ich eine Funktion habe, die eine FormData entgegennimmt und dann über die formularelemente iteriert. Ist das Element wieder ein Container für eine FormData (bspw. FS_List)   so ruft sich die Funktion selbst auf - damit hast du die verschiedenen Ebenen schon mal abgedeckt. Für alle weiteren formularelemente musst du entsprechend nur den link ermitteln - also für cms_input_link und dom/domtable. 18 Varianten dürftest du also nicht brauchen - eher ein paar für die verschiedenen container für die FormData + die Elemente, die direkt den link enthalten können. Wenn du detailliertere infos brauchst kannst du ja hier nochmal antworten oder mir eine pn schicken.

Gruß

Felix

0 Kudos

Hallo Felix,

ich tue mich aktuell noch schwer damit von der FormData auf das Link Element zu kommen.

Könntest du mir ein Beispiel geben wie das gemacht wird?

Viele Grüße

Nick

0 Kudos

Hallo Nick,

von der FormData holst du dir über .getForm().forms() die GomFormElemente. Für diese machst du dann einen Switch zur Unterscheidung - bspw. auf den Tag-Name (.getGomElementTag()).

  • Bei FS_LIST (Typ inline) und FS_CATALOG iterierst du über die Elemente und erhälst entweder eine IdProvidingFormData (FS_LIST SETIONTEMPLATES) oder eine FormData (FS_CATALOG), die du wieder an die Funktion übergeben kannst, oder du erhälst direkt einen Link (FS_LIST LINKTEMPLATES).
  • Bei CMS_INPUT_LINK erhälst du direkt einen Link
  • Bei CMS_INPUT_IMAGEMAP kriegst du Areas aus denen du dir direkt den LInk holen kannst.
  • Bei DOM / DOM_TABLE musst du über die Nodes iterieren und erhälst im Falle einer LinkDomNode auch wieder das Link-Objekt.

Für alle Eingabekomponenten musst du entsprechend schauen, wie du den Link bzw. die FormData ersetzt - das ist dann in der ODFS aber in der Regel gut beschrieben.

Bei weiteren Fragen einfach melden 😉

Viele Grüße

Felix

0 Kudos

Hallo Felix,

schon einmal Danke für deine Hilfe!

Ich steh allerdings immer noch auf dem Schlauch.

Das habe ich bisher:

LinkTemplate linkTemplate = linkTemplates.getTemplate(templateName);

ReferenceEntry[] referenceEntry = linkTemplate.getIncomingReferences();

this.masterLanguage = project.getMasterLanguage();

for (ReferenceEntry reference : referenceEntry) {

IDProvider referencedElement = reference.getReferencedElement();

if (!(referencedElement instanceof Section)) {

String name = referencedElement.getName();

Section section = (Section) referencedElement;

IDProvider body = section.getParent();

if (body == null) {

System.out.println("Unexpected error: Parent of Section (=body) was null for section with name = " + name);

continue;

}

IDProvider tmpParentPage = body.getParent();

if (tmpParentPage == null || !(tmpParentPage instanceof Page)) {

System.out.println("Unexpected error: Parent page for " + name + " was " + (tmpParentPage == null ? "null" : "of type of " + tmpParentPage.getClass().toString()));

continue;

}

Page parentPage = (Page) tmpParentPage;

FormData sectionData = section.getFormData();

Iterable<GomFormElement> iter = sectionData.getForm().forms();

for (GomFormElement gom : iter) {

if(gom.getGomElementTag().equalsIgnoreCase("CMS_INPUT_DOM")){ // Hier weiß ich, dass das aktuell GomFormElement ein CMS_INPUT_DOM ist

GomDom dom = (GomDom) gom;

GomLinkEditorList it = dom.getLinkEditors();

Iterator<GomNamedEntry> it2=it.iterator() ;

while (it2.hasNext()){

GomNamedEntry elem = it2.next();

if(elem.getGomElementTag().equalsIgnoreCase("LINKEDITOR")){

// Hier weiß ich, dass es ein LINKEDITOR ist. Da kann ich noch auf den korrekten referenznamen des Templates prüfen.

// Wie komm ich von einem GomNamedEntry auf ein Link Element?

// Ist der Ansatz denn korrekt?

}

}

}

}

    }

}

Scheinbar kann ich dann (Zeile 34) mit dem GomNamedEntry einfach gar nichts mehr anfangen?

Für mich sieht es zumindest so aus, dass ich mich für den Fall Input_Dom schon einmal bis ganz nach unten durchgehangelt habe an die Stelle, die ich gerne ändern würde.

Aber hier sehe ich aktuell keine Möglichkeit die Änderung durchzuführen?

Wo ist denn hier der Fehler?

Falscher Ansatz?

Viele Grüße

Nick

0 Kudos

Hallo Nick,

das GomFormElement nutzt du nur, um den Tag herauszufinden und holst dir dann die Value wieder über die FormData.

Hier mal ein Snippet, das ich öfters verwende:

/**

  * Das hier ist deine Methode um FormDatas allgemein zu migrieren:

  */

private FormData migrateFormData(FormData formData){

     for (GomFormElement form : formData.getForm().forms()) {

          // Hier unterscheidest du welche Art von FormField es ist

          String tag = form.getGomElementTag();

          switch (tag){

               case "CMS_INPUT_DOM":

                    FormField<?> domField = formData.get(language, form.name());

                    DomElement domElement = (DomElement) domField.get();

                    domField.set(migrateDom(domElement));

                    break;

               case "FS_LIST":

                    // Über Kinder ignorieren und migrateFormData für die IdProvidingFormData aufrufen

                    break;

               case "FS_CATALOG":

                    // Analog zu FS_LIST

                    break;

               case "CMS_INPUT_LINK":

                    // Die FormData vom Link holen und ebenfalls migrateFormData aufrufen

                    break;

               case "FS_REFERENCE":

                    // Hier dann die Referenz ersetzen

                    break;

          }

     }

     return formData;

}

/**

* Hier einfach über die DOM Kinder iterieren, den Link holen und das selbe Spiel wie bei CMS_INPUT_LINK machen

*/

private DomElement migrateDom(DomElement domElement){

     DefaultDomNode domRoot = domElement.getRoot();

     for (DomNode node : domRoot.getChildren(true)) {

          if (node.getNodeType() == de.espirit.firstspirit.access.editor.value.DomNodeType.LINK) {

               LinkDomNode linkNode = (LinkDomNode) node;

               Link link = linkNode.getLink();

               FormData linkFormData = link.getFormData();

               link.setFormData(migrateFormData(linkFormData));

               linkNode.setLink(link);

          }

     }

}

In meinem Fall rufe ich bei link.setFormData() wieder migrateFormData auf, weil ich mit dem Snippet die Referenzen auf eine Seite umbiege. Wenn du nur ein Text-Feld im Link änderst solltest du dafür dann ne eigene Methode noch hinzufügen oder es direkt im migrateDom machen.

Gruß

Felix

0 Kudos

Hallo Felix,

ich habe noch ein wenig rumprobiert und bin auf folgendes gekommen.

Zuerst iteriere ich über die ReferenceEntry[] Liste und hole mir da die Liste Iterable<GomFormElement> per .getForm().forms()

Da prüfe ich dann auf getGomElementTag().equalsIgnoreCase("CMS_INPUT_DOM") um an die DomElemt Felder zu kommen.

Habe ich so ein Element, iteriere ich über die Children (DomNode) und prüfe dann für einen bestimmten Fall, ob das Child Element ein Link ist.

if (node.getNodeType() == de.espirit.firstspirit.access.editor.value.DomNodeType.LINK)

Mein Plan war jetzt an dieser Stelle, dass ich ja "nur noch" an die URL aus dem CMS_INPUT_TEXT Feld rankommen und ändern muss.

Das habe ich so versucht:

LinkDomNode linkNode = (LinkDomNode) node;

Link link = linkNode.getLink();

link.setTemplate(linkTemplate);

Jetzt kann ich per link.get("st_ref") die URL auslesen. Per System.out. kann ich mir exakt den Wert ausgeben lassen, den ich ändern möchte.

Was mir jetzt nur fehlt ist, den geänderten Wert auch wieder zurück zu schreiben.

Versucht habe ich es wie folgt:

parentPage.setLock(true);

FormData lfd = link.getFormData();

String oldlink = link.get("st_ref").toString();

lfd.get(masterLanguage, "st_ref").set(oldlink.replace(searchPattern, replacePattern));

link.setFormData(lfd);

System.out.println("link.get(st_ref).toString(): " +link.get("st_ref").toString());

linkNode.setLink(link);

System.out.println("link Node gesetzt");

System.out.println("link.getTemplate(): " +link.getTemplate());

link.setTemplate(linkTemplate);

System.out.println("link.getTemplate(): " +link.getTemplate());

parentPage.release();

System.out.println("parentPage released");

parentPage.setLock(false);

System.out.println("parentPage setLock");

Der Plan war hier, zunächst einmal die Eltern Seite zu locken.

Anschließend über FormData den Link auszulesen und über die FormData zu ändern und wieder an den link zu setzen.

Laut den System.out Meldungen funktioniert es auch.

Ich bekomme den alten Link vor dem replace und den neuen nach dem set FormData.

Der Rest des Codes läuft auch einfach durch, es kommt zu keiner Fehlermeldung und ich bekomme die Logausgaben per System.out auf der Java Konsole angezeigt.

Allerdings wird in der Testseite nichts geändert. Der Inhalt bleibt nach wie vor der selbe.

Wo liegt denn hier der Fehler?

Ich bin immerhin soweit, dass ich sicher bin, dass ich auf dem richtigen Element bin. Jetzt frage ich mich nur, warum der Wert nicht gespeichert wird.

Hast du eine Idee?

Viele Grüße

Nick

0 Kudos

Hallo Nick,

auf jeden Fall solltest du schon mal das setTemplate weglassen. Und dir fehlt das speichern, sowie das setzen der FormDatas.

Zudem gibt es noch eine Besonderheit - bei mir hat es immer Probleme gemacht, wenn ich den Link aus der LinkNode "wiederverwendet" habe. Ich musste immer einen neuen erstellen und die FormData übertragen. Das könnte dann alles in allem so aussehen:

parentPage.setLock(true, true);

FormData frmData = section.getFormData();

FormField<?> domEditor = frmData.get(language, "st_text");

DomElement domElement = (DomElement) domEditor.get();

DefaultDomNode domRoot = domElement.getRoot();

for (DomNode node : domRoot.getChildren(true)) {

     if (node.getNodeType() == DomNodeType.LINK) {

          LinkDomNode linkNode = (LinkDomNode) node;

          Link link = linkNode.getLink();

          if ("textlinkexternal".equals(link.getTemplate().getUid())) {

               Link newLink = link.getTemplate().createLink(link.getLinkLanguage()); // Neuen Link erzeugen

               FormData linkFormData = link.getFormData();

               FormField<?> refField = linkFormData.get(null, "ref");

               String oldText = (String) refField.get();

               String newText = oldText.replaceAll("e", "a");

               refField.set(newText); // Neuer Wert dem FormField zuweisen

               newLink.setFormData(linkFormData); // Aktualisierte FormData dem Link zuweisen

               linkNode.setLink(newLink); // Link der LinkNode zuweisen

          }

     }

}

domEditor.set(domElement); // Wert im CMS_INPUT_DOM setzen

section.setFormData(frmData); // Aktualisierte FormData der Section zuweisen

parentPage.save();

parentPage.setLock(false, true);

Gruß

Felix

0 Kudos

Hallo Felix,

vielen Dank!

Das Skript funktioniert und jetzt werden auch die Werte ausgetauscht.

Jetzt hab ich nur noch vor das umzubauen, dass man die search und replace Werte per Formular eingeben kann und dann bin ich endlich durch.

Danke für deine Hilfe! Nur mit der API hätte ich glaube ich irgendwann aufgegeben Smiley Happy

Viele Grüße

Nick

Felix Reinhold schrieb:

Hallo Nick,

auf jeden Fall solltest du schon mal das setTemplate weglassen. Und dir fehlt das speichern, sowie das setzen der FormDatas.

Zudem gibt es noch eine Besonderheit - bei mir hat es immer Probleme gemacht, wenn ich den Link aus der LinkNode "wiederverwendet" habe. Ich musste immer einen neuen erstellen und die FormData übertragen. Das könnte dann alles in allem so aussehen:

  1. parentPage.setLock(true,true);
  2. FormDatafrmData=section.getFormData();
  3. FormField<?>domEditor=frmData.get(language,"st_text");
  4. DomElementdomElement=(DomElement)domEditor.get();
  5. DefaultDomNodedomRoot=domElement.getRoot();
  6. for(DomNodenode:domRoot.getChildren(true)){
  7. if(node.getNodeType()==DomNodeType.LINK){
  8. LinkDomNodelinkNode=(LinkDomNode)node;
  9. Linklink=linkNode.getLink();
  10. if("textlinkexternal".equals(link.getTemplate().getUid())){
  11. LinknewLink=link.getTemplate().createLink(link.getLinkLanguage());//NeuenLinkerzeugen
  12. FormDatalinkFormData=link.getFormData();
  13. FormField<?>refField=linkFormData.get(null,"ref");
  14. StringoldText=(String)refField.get();
  15. StringnewText=oldText.replaceAll("e","a");
  16. refField.set(newText);//NeuerWertdemFormFieldzuweisen
  17. newLink.setFormData(linkFormData);//AktualisierteFormDatademLinkzuweisen
  18. linkNode.setLink(newLink);//LinkderLinkNodezuweisen
  19. }
  20. }
  21. }
  22. domEditor.set(domElement);//WertimCMS_INPUT_DOMsetzen
  23. section.setFormData(frmData);//AktualisierteFormDataderSectionzuweisen
  24. parentPage.save();
  25. parentPage.setLock(false,true);

Gruß

Felix

0 Kudos