Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: Step 24. 01. 2019, 22:35:30
-
potrebuju upravit jeden text v svg. Zdanlive jednoduche, ale nejak jsem se zaseknul. Nedokazu formulovat XPATH pro Text1. Nejvetsi nadeje jsem daval .//*[@id="TEXT1_ID"]/tspan pripadne tomuto .//*[@id="TEXT1_ID"]/tspan/text() . Ovsem to nejak nefunguje. Pak jsem zkusil asi tak milion jinych blbosti. Pouzival jsem na to online validator: https://codebeautify.org/Xpath-Tester. Asi jsem na tom neco zle nepochopil :(
<?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="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="testing.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.7"
inkscape:cx="162.05782"
inkscape:cy="758.41218"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1581"
inkscape:window-height="1028"
inkscape:window-x="1912"
inkscape:window-y="22"
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="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;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"
x="155.71429"
y="178.07649"
id="TEXT1_ID"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4138"
x="155.71429"
y="178.07649">Text1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;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"
x="155.71429"
y="238.07649"
id="TEXT2_ID"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4142"
x="155.71429"
y="238.07649">Text2 <tspan
style="font-weight:bold"
id="tspan4144">Text</tspan>3 Text4</tspan></text>
</g>
</svg>
-
co tohle?!
(//*[@id="TEXT1_ID"])/*/text()
-
co tohle?!
(//*[@id="TEXT1_ID"])/*/text()
Luxusni!
Ale proc?
(//*[@id="TEXT1_ID"])/*/text() - OK
//*[@id="TEXT1_ID"]/*/text() - OK
//*[@id="TEXT1_ID"]/tspan/text() - NOK
Proc tam ten tspan nefunguje?
-
co tohle?!
(//*[@id="TEXT1_ID"])/*/text()
Luxusni!
Ale proc?
(//*[@id="TEXT1_ID"])/*/text() - OK
//*[@id="TEXT1_ID"]/*/text() - OK
//*[@id="TEXT1_ID"]/tspan/text() - NOK
Proc tam ten tspan nefunguje?
kvuli defaultnimu namespace... bud ho parser nejak pouzije (zalezi, jestli to umi), nebo ho dej docasne do pryc (smazni xmlns="http://www.w3.org/2000/svg") v <svg> a pak ho tam zase vrat...
-
Zkusil bych XMLStarlet:
xmlstarlet sel -t -m '//*[@id="TEXT1_ID"]/_:tspan' -v 'text()' picture.svg
Zvládne i editaci textu v elementu
xmlstarlet ed -u '//*[@id="TEXT1_ID"]/_:tspan' -v 'Nový text' picture.svg
-
Máte tam (správně) jmenné prostory, takže je potřeba je používat i v XPath. Pozor na to, že mapování prefixů na jmenné prostory se dělá externě (není to součást XPath výrazu, ale musíte procesoru, kterým XPath zpracováváte, to mapování předat jako parametr; a nepřebírají se do XPath ani prefixy jmenných prostorů definované v dokumentu). Pak bude fungovat //*[@id="TEXT1_ID"]/svg:tspan/text() (a musíte předat mapování svg → http://www.w3.org/2000/svg).
Druhá možnost je porovnávat QName přímo ve výrazu, ale pak nemůžete použít zkrácený zápis: //*[@id="TEXT1_ID"]/*[name() = 'tspan']/text(). Tím výrazem *[name() = 'tspan'] řeknete, že hledáte všechny elementy, které splňují podmínky v hranatých závorkách, tedy že jejich plné jméno (včetně prefixu) je tspan. Protože tspan je v defaultním jmenném prostoru, nemá žádný prefix.
Když jste použil zkrácené porovnání na QName elementu ale bez přiřazených prefixů jmenných prostorů, hledal se element tspan z prázdného jmenného prostoru, a takový v dokumentu není.
-
Proc tam ten tspan nefunguje?
kvuli defaultnimu namespace... bud ho parser nejak pouzije (zalezi, jestli to umi), nebo ho dej docasne do pryc (smazni xmlns="http://www.w3.org/2000/svg") v <svg> a pak ho tam zase vrat...
Takové mazání a vracení namespace je značně nesystémové a je cestou do pekel. Je třeba se naučit s namespace pracovat, jinak bude docházet k zmatkům. Zpočátku je to sice poněkud bolestivé, ale je nutné ten čas do toho investovat.
-
Druhá možnost je porovnávat QName přímo ve výrazu, ale pak nemůžete použít zkrácený zápis: //*[@id="TEXT1_ID"]/*[name() = 'tspan']/text(). Tím výrazem *[name() = 'tspan'] řeknete, že hledáte všechny elementy, které splňují podmínky v hranatých závorkách, tedy že jejich plné jméno (včetně prefixu) je tspan. Protože tspan je v defaultním jmenném prostoru, nemá žádný prefix.
To bude fungovat pouze za předpokladu, že svg je default namespace. Pokud chcu porovnávat jenom element name (bez namespace), je třeba použít local-name() . Pokud chcu porovnávat celé element name, je nejlepší si namespace v XPath zaregistrovat. Tohle je mix, který bude nejspíš dlouho fungovat, až se jednoho dne na jiných, ale přesto stejných datech, rozbije.
-
To bude fungovat pouze za předpokladu, že svg je default namespace. Pokud chcu porovnávat jenom element name (bez namespace), je třeba použít local-name() . Pokud chcu porovnávat celé element name, je nejlepší si namespace v XPath zaregistrovat. Tohle je mix, který bude nejspíš dlouho fungovat, až se jednoho dne na jiných, ale přesto stejných datech, rozbije.
Ale ten element tspan je v default namespace, podívejte se na ten dokument. local-name() nechci použít, protože to pak porovnává bez ohledu na namespace – kdyby tam byl element tspan z jiného namespace, vyhoví podmínce také.
Ano, nejlepší je namespace v XPath zaregistrovat, protože pak je XPath nezávislý na tom, jak jsou nadefinované prefixy v konkrétním dokumentu.