I need with xmlstarlet
or yq
to copy the content of an element into an other element, placing to the start or the end of it.
Using this kind of xml:
<products>
<product>
<id>01</id>
<Title><![CDATA[ Product 1 Title ]]></Title>
<Dimensions><![CDATA[ S ]]></Dimensions>
<Size><![CDATA[ for Adult ]]></Size>
</product>
<product>
<id>02</id>
<Title><![CDATA[ Product 2 Title ]]></Title>
<Dimensions><![CDATA[ Medium ]]></Dimensions>
<Size><![CDATA[ for Kids ]]></Size>
</product>
</products>
i try to copy the content of each Dimensions and Size elements into the start or end of Title element, using this bash:
xmlstarlet ed -u /products/product/Title -x "concat(/products/product/Title,' ',/products/product/Dimensions/text(),' ',/products/product/Size)" sourcefile.xml > outputfile.xml
but the problem is that the Title of first product element is copied in every other product element. I expect:
<Title><![CDATA[ Product 1 Title S for Adult]]></Title>
<Title><![CDATA[ Product 2 Title Medium for Kids]]></Title>
but i receive:
<Title><![CDATA[ Product 1 Title S for Adult]]></Title>
<Title><![CDATA[ Product 1 Title S for Adult]]></Title>
CodePudding user response:
Which implementation of yq
do you mean?
Using mikefarah/yq:
yq
provides the options -p
and -o
to set the input and output format; both take the parameter xml
or x
.
yq -o xml -p xml '
.products.product[] |= (.Title = " " .Dimensions " " .Size)
' sourcefile.xml > outputfile.xml
Using kislyuk/yq:
To manipulate XML files, yq
provides xq
, which converts the XML file into JSON, then uses stedolan/jq for manipulation. The -x
option converts the output back to XML:
xq -x '
.products.product[] |= (.Title = " " .Dimensions " " .Size)
' sourcefile.xml > outputfile.xml
Output
For both, the outputfile.xml
should then look like:
<products>
<product>
<id>01</id>
<Title>Product 1 Title S for Adult</Title>
<Dimensions>S</Dimensions>
<Size>for Adult</Size>
</product>
<product>
<id>02</id>
<Title>Product 2 Title Medium for Kids</Title>
<Dimensions>Medium</Dimensions>
<Size>for Kids</Size>
</product>
</products>
Using xmlstarlet
Here you can go with:
xmlstarlet ed -u /products/product/Title -x '
concat(../Title, ../Dimensions, ../Size)
' sourcefile.xml > outputfile.xml
Then, the outputfile.xml
would then look like:
<?xml version="1.0"?>
<products>
<product>
<id>01</id>
<Title> Product 1 Title S for Adult </Title>
<Dimensions><![CDATA[ S ]]></Dimensions>
<Size><![CDATA[ for Adult ]]></Size>
</product>
<product>
<id>02</id>
<Title> Product 2 Title Medium for Kids </Title>
<Dimensions><![CDATA[ Medium ]]></Dimensions>
<Size><![CDATA[ for Kids ]]></Size>
</product>
</products>
Note: The important thing (for all three approaches) is to traverse to each product
, and collect the items for concatenation from their children only. With both yq
implementations, this is achieved using the update operator |=
. For xmlstarlet
you need to move with relative XPaths using ..
to go up one level.
Also note, that there are formatting/encoding differences between these tools. Use them according to your needs.