I am new to xmlstarlet so hoping this answer is a simple one.
I am writing a script to modify Inkscape SVG files from the command line. I chose the tool xmlstarlet.
After testing the command syntax on test files, I am having trouble on the real SVG files. I think the use of namespaces is throwing me off.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="603"
height="1000"
viewBox="0 0 159.54375 264.58334"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r"
sodipodi:docname="test.svg"
inkscape:export-filename="/home/user/dev/inkscape/test/1.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2">
<linearGradient
inkscape:collect="always"
id="linearGradient6204">
<stop
style="stop-color:#8f1a22;stop-opacity:1;"
offset="0"
id="stop6200" />
<stop
style="stop-color:#8f1a22;stop-opacity:0;"
offset="1"
id="stop6202" />
</linearGradient>
</defs>
</svg>
I want to change Gradient6204
to Gradient9999
.
I wrote this command, which does not work (just returns the original file).
xmlstarlet ed -u "/svg/defs/linearGradient[@id='linearGradient6204']/@id" -v 'linearGradient9999' text.txt
I also tried again, adding the namespaces with -N but no luck. I found that if I delete the line:
xmlns="http://www.w3.org/2000/svg"
from the file then the command I wrote above works.
What is the proper syntax for updating the SVG file above in the way I described?
XPath treats the empty prefix as the null namespace. In other words, only prefixes mapped to namespaces can be used in XPath queries. This means that if you want to query against a namespace in an XML document, even if it is the default namespace, you need to define a prefix for it.
Introduction to XPath namespace. In an XML document, namespaces are used to provide uniquely named components and attributes. A namespace is made up of two parts: a prefix and a URL. This indicates the location of a document that defines the namespace in question.
XML Namespaces - The xmlns Attribute When using prefixes in XML, a namespace for the prefix must be defined. The namespace can be defined by an xmlns attribute in the start tag of an element. The namespace declaration has the following syntax. xmlns:prefix="URI".
Adding -N s=http://www.w3.org/2000/svg
and then using the s:
namespace prefix works:
xmlstarlet ed -N s=http://www.w3.org/2000/svg -u "/s:svg/s:defs/s:linearGradient[@id='linearGradient6204']/@id" -v 'linearGradient9999' text.txt
Starting with XMLStarlet v1.2.1, an explicit command line definition for the default namespace (such as is the case with OP's SVG file) can be avoided via use of an automated binding of _
to the default namespace:
1.3. A More Convenient Solution
XML documents can also use different namespace prefixes, on any element in the document. In order to handle namespaces with greater ease, XMLStarlet (versions 1.2.1+) will use the namespace prefixes declared on the root element of the input document. The default namespace will be bound to the prefixes
_
andDEFAULT
(in versions 1.5.0+).
So, the above command line could be re-written as:
xmlstarlet ed -u "/_:svg/_:defs/_:linearGradient[@id='linearGradient6204']/@id" -v 'linearGradient9999' text.txt
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With