Anonymous
Not applicable

Keine korrekte Unterstützung von XPath in Beanshell-Console?

Hallo Community,

ich versuche gerade die FS_ID des Typs eines Links innerhalb eines CMS_INPUT_DOM per Skript auszulesen. Das geht (so meine Vermutung) am einfachsten per XPath, da der Inhalt des DOMs eine XML-Struktur ist:

<DOM>

    <p_story>

        <CMS_LINK linktemplate="embedded_teaser" type="genericlink">

            <TEMPLATECONTENT>

                <CMS_VALUE name="lt_teaserFormat">

                    <LANG id="$" set="1">

                        <SEL>

                            <VALUE>427</VALUE>

                        </SEL>

                    </LANG>

                </CMS_VALUE>

                <CMS_VALUE name="lt_story">

                    <LANG id="$" set="1" />

                </CMS_VALUE>

                <CMS_VALUE name="lt_embeddableFormat">

                    <LANG id="$" set="1" />

                </CMS_VALUE>

                <CMS_VALUE name="lt_embeddedElementCaption">

                    <LANG id="$" set="1">

                        <TEXT>Step 1: New Kids auf alten Bildern</TEXT>

                    </LANG>

                </CMS_VALUE>

                <CMS_VALUE name="lt_embeddedElementAlignment">

                    <LANG id="$" set="1">

                        <SEL>

                            <VALUE>centered</VALUE>

                        </SEL>

                    </LANG>

                </CMS_VALUE>

            </TEMPLATECONTENT>

        </CMS_LINK>

    </p_story>

[...]

</DOM>

Ich möchte nun genau die "427" herausfiltern. Hierfür habe ich mir das DOM-XML gespeichert und in Firefox mit AddOn "XmlUtil" geöffnet, da es damit möglich ist einen XPath-Ausdruck für eine bestimmte Node zu generieren.

Dieser XPath-Ausdruck lautet:

/DOM/p_story/CMS_LINK[@linktemplate='embedded_teaser' and @type='genericlink']/TEMPLATECONTENT/CMS_VALUE[@name='lt_teaserFormat']/LANG[@id='§' and @set='1']/SEL/VALUE

oder gekürzt

//CMS_LINK[@linktemplate='embedded_teaser']/TEMPLATECONTENT/CMS_VALUE[@name='lt_teaserFormat']/LANG/SEL/VALUE

Damit sollte es eigentlich möglich sein auf dem Rootnode des DOMs den entsprechenden Node herauszufiltern. Man kann noch die Methode text() anhängen, aber die Node würde mir schon reichen.

Jetzt zum Verhalten von FirstSpirit:

In einer Beanshell-Console suche ich mir das Entity mit dem DOM-Text

story = e.schema.session.find("stories", 1111);

dom = e.getDataset(story).getFormData().get(null, "cs_mainText").get().get();

xpathString = "//CMS_LINK[@linktemplate='embedded_teaser']/TEMPLATECONTENT/CMS_VALUE[@name='lt_teaserFormat']/LANG/SEL/VALUE";

xpath = javax.xml.xpath.XPathFactory.newInstance().newXPath();

xpath.evaluate(xpathString, dom, javax.xml.xpath.XPathConstants.NODE);

Ich erwartete hier eigentlich, dass nun die gewünschte Node rauspurzelt. Stattdessen erhalte ich "null". Baue ich sukzessive den XPath-Ausdruck zurück, erhalte ich in egal welcher Kombination immer "null". Einzig folgender Ausdruck scheint zu funktionieren:

//CMS_LINK

Hier bekomme ich die CMS_LINK-Node. Hangele ich mich nun mittels node.getFirstChild()-Methode durch die einzelnen Nodes, dann bekomme ich genau die erwarteten geliefert, die XPath in FirstSpirit aber wehement nicht finden will:

bsh % node = xpath.evaluate("//CMS_LINK", dom, javax.xml.xpath.XPathConstants.NODE);

<[CMS_LINK: null]>

bsh % node.getFirstChild();

<[TEMPLATECONTENT: null]>

bsh % node.getFirstChild().getFirstChild();

<[CMS_VALUE: null]>

bsh % node.getFirstChild().getFirstChild().getAttribute("name");

<lt_teaserFormat>

bsh % node.getFirstChild().getFirstChild().getFirstChild();

<[LANG: null]>

bsh % node.getFirstChild().getFirstChild().getFirstChild().getFirstChild();

<[SEL: null]>

bsh % node.getFirstChild().getFirstChild().getFirstChild().getFirstChild().getFirstChild();

<[VALUE: null]>

bsh % node.getFirstChild().getFirstChild().getFirstChild().getFirstChild().getFirstChild().getTextContent();

<427>

Nicht einmal der XPath-Ausdruck

//CMS_LINK/TEMPLATECONTENT

wird gefunden.

WTF?!

0 Kudos
3 Replies
Peter_Jodeleit
Crownpeak employee

Wenn ich das Beispiel nachvollziehe (wobei ich mir die org.w3c.dom.Document-Instanz aus deinem angegebenem XML erzeuge) funktioniert es wie gewünscht. Also muss der "Fehler" in den ersten beiden Zeilen deines Skriptes liegen, den Teil kann ich natürlich nicht nachvollziehen.

Du lässt dich auch nicht von der "toString"-Ausgabe der Knoten-Implementierung von Java 'ablenken'?

bsh % result = xpath.evaluate(xpathString, document, XPathConstants.NODE);

<[VALUE: null]>

bsh % converter.toXML(result);

<<VALUE>427</VALUE>>

Peter
0 Kudos
Anonymous
Not applicable

Hi Peter,

Das hier ist wirklich mein komplettes Testskript gewesen. Das CMS_INPUT_DOM besitzt im Text einen Link. Das war's eigentlich schon.

story = e.schema.session.find("stories", 1111);
dom = e.getDataset(story).getFormData().get(null, "cs_mainText").get().get(); // --> liefert Element
xpathString = "//CMS_LINK[@linktemplate='embedded_teaser']/TEMPLATECONTENT/CMS_VALUE[@name='lt_teaserFormat']/LANG/SEL/VALUE";
xpath = javax.xml.xpath.XPathFactory.newInstance().newXPath();
xpath.evaluate(xpathString, dom, javax.xml.xpath.XPathConstants.NODE);

Die Ausgabe des evaluate() ist

<null>

Speichere ich mir diesen Wert in einer Variablen und rufe getClass() auf, dann bekomme ich einen NPE wie erwartet. Daher vermutlich keine falsche toString()-Interpretation.

// Error: // Uncaught Exception: bsh.TargetError: null : at Line: 1 : in file: <unknown file> : .getClass ( )

Ich kann mir zwar aus dem Element das zugehörige Document über getOwnerDocument() geben lassen. Das ändert leider am XPath-Ergebnis nichts. Dieses Document ist ziemlich ... leer.

Kopiere ich mir das XML in eine Java-Klasse und führe dort folgenden (Java-)Code aus, findet XPath ohne Probleme meine gewünschte Node.

ClassPathResource r = new ClassPathResource("testDocuments/dom_embedded_teaser.xml");

Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.getInputStream());

String xpathString = "//CMS_LINK[@linktemplate='embedded_teaser' and @type='genericlink']/TEMPLATECONTENT/CMS_VALUE[@name='lt_teaserFormat']/LANG/SEL/VALUE";

XPath xpath = XPathFactory.newInstance().newXPath();

System.out.println(xpath.evaluate(xpathString, doc, XPathConstants.NODE));

Ergebnis:

[VALUE: null]

Ich vermute es liegt an dem vom FormField gelieferten DomElement, aus dem ich mir wiederum das Element ziehe? Wie genau hast du in Beanshell das Document erstellt?

0 Kudos
Anonymous
Not applicable

Wahnsinn, es liegt anscheinend wirklich daran, dass das direkt aus dem FormField gewonnene DomElement (respektive Element) zu nichts nütze ist...

Nimmt man direkt das Entity, das, so dachte ich, durch FormData/FormField ersetzt werden sollte, parst den Aufruf von entity.getValue("db_spalten_name") zu einem org.w3c.dom.Document, so lässt sich der XPath-Ausdruck ohne Probleme darauf ausführen:

entity = e.schema.session.find("stories", 1234);

document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(entity.getValue("main_text").toString())));

xpath.evaluate(xpathString, document, XPathConstants.NODE);

Ergebnis:

[VALUE: null]

0 Kudos