vreden123
Anmeldungsdatum: 24. Dezember 2012
Beiträge: 17
|
Hallo, ich habe folgenden String:
string=<title>Google.de</title> Wie kann ich es machen das ich "Google.de" in einem gesonderten String bekomme?
Ich habe schon gegoogelt und herausgefunden das ich es mit der Funktion "sed" machen kann, aber das will noch nicht so ganz klappen. Gruß,
vreden123
|
Vain
Anmeldungsdatum: 12. April 2008
Beiträge: 2505
|
Servus, „sed “ ist ein Programm und keine Funktion. ☺ Hier reicht vielleicht auch einfache Parameter Expansion: | #!/bin/bash
string='<title>Google.de</title>'
string=${string#*>}
string=${string%<*}
echo "$string"
|
Erklärung, wie das so funktioniert: http://mywiki.wooledge.org/BashFAQ/073 Obligatorische Warnung: Prinzipiell ist bei HTML/XML eigentlich ein Tool wie „xmlstarlet “ angesagt. Bei solch einfachen Aufgaben wie dieser hier muss man es nicht verwenden – aber wenn es komplizierter werden sollte, dann kommst du mit der Shell oder „sed “ nicht mehr weit.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13174
|
Herzlich willkommen hier im Forum! vreden123 schrieb: ich habe folgenden String:
string=<title>Google.de</title> Wie kann ich es machen das ich "Google.de" in einem gesonderten String bekomme?
Ich habe schon gegoogelt und herausgefunden das ich es mit der Funktion "sed" machen kann, aber das will noch nicht so ganz klappen.
Ich würde eher ein Tool nehmen, das für die Bearbeitung von XML oder HTML ausgelegt ist. Du kannst z.B. xmlstarlet nehmen, um etwas aus dem Dokument zu selektieren. Da ich üblicherweise Ruby programmiere, nehme ich in dem Fall dann Nokogiri. In beiden Fällen solltest Du mit diesem XPath zum Ziel kommen: //title[1]/text() Ciao robert Oh, Vain war schneller. ☺ Edit: musste der Syntaxerkennung ein Schnippchen schlagen.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Da kann ich meinen Vorrednern nur zustimmen: für solche Tag-orientierten Dinge sollte man xmlstarlet (1) nehmen ! (ein paar Tips, wie man mit XML umgehen kann, findest Du schonmal hier bei mir, und sonst hier im Unterforum) Auch wenn es nicht ganz sauber ist, kann man natürlich auch mit sed (2) oder einer Parameter Expansion (3) die Tags weglöschen: track@lucid:~$ string='<title>Google.de</title>'
track@lucid:~$ echo "$string" | xmlstarlet sel -t -m //title -v . # (1)
Google.de
track@lucid:~$ echo "$string" | sed 's|</*title>||g' # (2)
Google.de
track@lucid:~$ echo "${string//<?(\/)title>/}" # (3)
Google.de (Mit passender Musterersetzung sogar in einem Schritt) LG, track (Tick, Trick und Track wieder beim gemeinsamen Service, am Heiligabend ... 😉 )
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13174
|
track schrieb: (Tick, Trick und Track wieder beim gemeinsamen Service, am Heiligabend ... 😉 )
🤣 Schön! Uns ist auch nix heilig... 😉 So, ich pack dann mal weiter Geschenke ein! robert
|
Vain
Anmeldungsdatum: 12. April 2008
Beiträge: 2505
|
track schrieb: track@lucid:~$ string='<title>Google.de</title>'
track@lucid:~$ echo "$string" | xmlstarlet sel -t -m //title -v .
Google.de
Oh, das geht ja doch. Ich ging davon aus, dass „xmlstarlet “ immer ein komplettes Dokument haben will. Aber wenn das Ding auch mit derlei Fetzen zurechtkommt… 👍 (Tick, Trick und Track wieder beim gemeinsamen Service, am Heiligabend ... 😉 )
Wieso, ist heute was besonderes? 😬 😉
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Vain schrieb: ... dass „xmlstarlet “ immer ein komplettes Dokument haben will.
xmlstarlet verlangt definitiv ein "wohlgeformtes" Dokument, das stimmt. Aber das heißt ja nur, dass die Tag-Paare im Bäumchen stimmen, und dass es genau 1 Wurzelelement gibt. - und das passt hier beides ... LG, und dennoch gesegnete Weihnachten, ☺ track
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13174
|
track schrieb: track@lucid:~$ string='<title>Google.de</title>'
track@lucid:~$ echo "$string" | xmlstarlet sel -t -m //title -v . # (1)
Google.de
Warum machst Du nicht einfach dies hier? | $ echo '<title>Google.de</title>' | xmlstarlet sel -t -v '//title'
Google.de
|
Ciao robert
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
rklm schrieb: Warum machst Du nicht einfach dies hier?
Stimmt, geht auch. Der Unterschied zwischen xmlstarlet sel -t -m //title -v . und xmlstarlet sel -t -v //title ist der, dass -m alle entsprechenden Knoten abklappert (quasi als Schleife), und -v immer nur den Inhalt von einem Knoten ausgibt. Hier ist das egal, aber bei mehreren Knoten nicht: track@lucid:~$ echo '<xml> <title>Google1.de</title> <title>Google2.de</title> </xml>' | xmlstarlet sel -t -v '//title'
Google1.de
track@lucid:~$ echo '<xml> <title>Google1.de</title> <title>Google2.de</title> </xml>' | xmlstarlet sel -t -m '//title' -v .
Google1.deGoogle2.de LG, track
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13174
|
track schrieb: rklm schrieb: Warum machst Du nicht einfach dies hier?
Stimmt, geht auch. Der Unterschied zwischen xmlstarlet sel -t -m //title -v . und xmlstarlet sel -t -v //title ist der, dass -m alle entsprechenden Knoten abklappert (quasi als Schleife), und -v immer nur den Inhalt von einem Knoten ausgibt. Hier ist das egal, aber bei mehreren Knoten nicht: track@lucid:~$ echo '<xml> <title>Google1.de</title> <title>Google2.de</title> </xml>' | xmlstarlet sel -t -v '//title'
Google1.de
track@lucid:~$ echo '<xml> <title>Google1.de</title> <title>Google2.de</title> </xml>' | xmlstarlet sel -t -m '//title' -v .
Google1.deGoogle2.de
| $ echo '<xml> <title>Google1.de</title> <title>Google2.de</title> </xml>' | xmlstarlet sel -t -v '//title'
Google1.de
Google2.de
$ xmlstarlet --version
1.3.1
compiled against libxml2 2.7.8, linked with 20800
compiled against libxslt 1.1.26, linked with 10126
|
Hm... robert
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
... eigenartig ! track@lucid:~$ xmlstarlet --version
1.0.1
track@lucid:~$ xmlstarlet sel -C -t -v '//title'
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common"
xmlns:math="http://exslt.org/math"
xmlns:date="http://exslt.org/dates-and-times"
xmlns:func="http://exslt.org/functions"
xmlns:set="http://exslt.org/sets"
xmlns:str="http://exslt.org/strings"
xmlns:dyn="http://exslt.org/dynamic"
xmlns:saxon="http://icl.com/saxon"
xmlns:xalanredirect="org.apache.xalan.xslt.extensions.Redirect"
xmlns:xt="http://www.jclark.com/xt"
xmlns:libxslt="http://xmlsoft.org/XSLT/namespace"
xmlns:test="http://xmlsoft.org/XSLT/"
extension-element-prefixes="exslt math date func set str dyn saxon xalanredirect xt libxslt test"
exclude-result-prefixes="math str">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:param name="inputFile">-</xsl:param>
<xsl:template match="/">
<xsl:call-template name="t1"/>
</xsl:template>
<xsl:template name="t1">
<xsl:value-of select="//title"/>
</xsl:template>
</xsl:stylesheet> Möglicherweise ist das Verhalten nicht eindeutig definiert, wenn kein Knoten ausgewählt wurde ? (→ darum zum Vergleich mal den XSL-Dump) Aber abgesehen davon: bei manchen Sachen habe ich auch immer mal das Gefühl, xmlstarlet sei noch "recht jung" ... LG, track
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13174
|
track schrieb: ... eigenartig !
☺ Bei mir sieht das so aus: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | $ xmlstarlet sel -C -t -v '//title'
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="//title"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
|
Möglicherweise ist das Verhalten nicht eindeutig definiert, wenn kein Knoten ausgewählt wurde ?
Was meinst Du damit? Wir haben doch in beiden Varianten einen Knoten ausgewählt. Ich würde eher annehmen, dass die Ausgabe nur eines Knotens mit -v in Deiner Version ein Bug ist. Wenn man nur eine Ausgabe haben will, dann kann man das immer noch durch die Verwendung von [1], [first()] oder [last()] im XPath erreichen. Auf jeden Fall wäre es merkwürdig, die Angabe "Ausgabe des Wertes" mit der Funktionalität "nur den ersten Knoten ausgeben" zu mischen. Dafür hätte ich dann mindestens eine separate Option erwartet.
(→ darum zum Vergleich mal den XSL-Dump)
Sieht deutlich anders aus. ☺ Wenn ich das richtig deute, ist in meiner Version explizit eine Schleife kodiert, die über alle Fundstellen geht.
Aber abgesehen davon: bei manchen Sachen habe ich auch immer mal das Gefühl, xmlstarlet sei noch "recht jung" ...
☺ Ich habe bisher meistens Ruby und Nokogiri verwendet, aber die Ladezeiten von xmlstarlet sind für solche einfachen Manipulationen deutlich besser. Von daher werde ich es mal öfter benutzen. Ciao robert
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Was meinst Du damit? Wir haben doch in beiden Varianten einen Knoten ausgewählt.
Nee, bei der Version ohne -m haben wir uns auf die implizite Vorauswahl eines Knotens verlassen ! - das war der Punkt. Und ja, ich würde auch davon ausgehen, dass meine Version noch was buggy ist ... Bei Deinem XSL steht die entscheidende Zeile: <xsl:for-each select="exslt:node-set($select)[position()>1]"> und bei mir nicht. Von daher macht er in beiden Fällen schon das, was er sich da an XSL gebaut hat ... Aber ok, muss man also ggf. berücksichtigen, wenn man jemandem einen bestimmten xmlstarlet- Befehl vorschlägt ! (ganz auf der sicheren Seite wäre man, wenn man selber einen XSL baut, und den dann an xmlstarlet verfüttert ! - aber wer tut das schon ?!) track
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13174
|
track schrieb: Bei Deinem XSL steht die entscheidende Zeile: <xsl:for-each select="exslt:node-set($select)[position()>1]"> und bei mir nicht. Von daher macht er in beiden Fällen schon das, was er sich da an XSL gebaut hat ...
Erst hatte ich mich über die Konstruktion gewundert, dass nicht alle Elemente mit der Schleife abgearbeitet werden. Aber dann ist mir aufgefallen, dass in der Schleife jeweils das letzte Zeichen gelöscht wird, was scheinbar der Zeilenumbruch ist. Ein wenig weitere Herumspielerei: | $ alias e="echo '<a><b>x</b><b>y</b></a>'"
$ e|xmlstarlet sel -t -v '//b'
x
y
$ e|xmlstarlet sel -t -v '//b/text()'
x
y
$ e|xmlstarlet sel -t -m '//b' -v .
xy
$ e|xmlstarlet sel -t -m '//b/text()' -v .
xy
|
Dann schauen wir uns mal das XSL an: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 | $ xmlstarlet sel -C -t -v '//b'
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="//b"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
$ xmlstarlet sel -C -t -v '//b/text()'
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="//b/text()"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
$ xmlstarlet sel -C -t -m '//b' -v .
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="//b">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="."/>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
$ xmlstarlet sel -C -t -m '//b/text()' -v .
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="//b/text()">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="."/>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
|
Unterschiede:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | $ diff -wU3 <(xmlstarlet sel -C -t -v '//b') <(xmlstarlet sel -C -t -v '//b/text()')
--- /dev/fd/63 2012-12-25 17:30:41.342913502 +0100
+++ /dev/fd/62 2012-12-25 17:30:41.338913302 +0100
@@ -3,7 +3,7 @@
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:call-template name="value-of-template">
- <xsl:with-param name="select" select="//b"/>
+ <xsl:with-param name="select" select="//b/text()"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="value-of-template">
$ diff -wU3 <(xmlstarlet sel -C -t -v '//b') <(xmlstarlet sel -C -t -m '//b' -v .)
--- /dev/fd/63 2012-12-25 17:31:01.471686990 +0100
+++ /dev/fd/62 2012-12-25 17:31:01.471686990 +0100
@@ -2,9 +2,11 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
+ <xsl:for-each select="//b">
<xsl:call-template name="value-of-template">
- <xsl:with-param name="select" select="//b"/>
+ <xsl:with-param name="select" select="."/>
</xsl:call-template>
+ </xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
|
Jetzt kapiere ich allerdings nicht, warum in der Variante mit "-v ." die Zeilenumbrüche fehlen. Es wird doch immer ein Knoten übergeben, so dass das Löschen des letzten Zeichens (0x10 = 16 = ASCII DEL) in Zeile 52 in der Schleife im "value-of-template" gar nicht zum Tragen kommt. Wenn überhaupt, müsste es doch genau anders herum sein. Wie erklärst Du Dir das?
Aber ok, muss man also ggf. berücksichtigen, wenn man jemandem einen bestimmten xmlstarlet- Befehl vorschlägt !
Zumindest braucht es einen Warnhinweis. ("Zu Risiken und Nebenwirkungen fragen Sie Ihren Softwareentwickler oder Programmierer.")
(ganz auf der sicheren Seite wäre man, wenn man selber einen XSL baut, und den dann an xmlstarlet verfüttert ! - aber wer tut das schon ?!)
Genau: der Witz ist ja gerade, dass man mit relative wenig Aufwand (einen XPath-Ausdruck schreiben) zu dem Ergebnis kommt. Wenn man sich auch noch in XSLT einarbeiten muss, steigt der Aufwand erheblich. Da würde ich dann mit Sicherheit auf Ruby + Nokogiri zurückgreifen, weil das wirklich gut funktioniert. Ciao robert
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Also, der normale -v - Befehl hängt bei mir freiwillig keinen Zeilenumbruch an, dafür gibt es ja extra den Befehl -n. Ist also offenbar ein Feature, kein Bug. Zu den Details müsste man sich tatsächlich den XSL angucken, denn das ist der interne Code, den er sich erzeugt und dann abarbeitet. Einen (standardisierten) XSL braucht man allerdings nicht wirklich von der Pike auf zu schreiben, sondern kann ihn einfach aus xmlstarlet exportieren, dann nacharbeiten und anschließend wieder an xmlstarlet verfüttern. - das wäre am ehesten der Weg, den man nähme.
Edit: Zu Deiner Frage oben habe ich nochmal überlegt: Eigentlich müsste xmlstarlet sel -t -v '//title' ja identisch sein mit xmlstarlet sel -t -m / -v '//title' - und das ist es bei mir auch ! (bei Dir auch ?) - ich erinnere mich ganz dunkel, dass es immer mal Probleme gab, wenn man die Knotenauswahl mit -m wegließ. Das war wohl auch der Grund, weshalb ich per Gewohnheit immer diese Schreibweise benutze ... (So viel zu Deiner ursprünglichen Frage - das war mir nur entfallen)
track
|