Repeat attribute with xmlstarlet - xmlstarlet

I'm trying to use XMLstarlet to convert some data from XML format to CSV. My data is formatted as
<!-- mydata.xml -->
<alldata>
<data id="first">
<coord><x>0</x><y>5</y></coord>
<coord><x>1</x><y>4</y></coord>
<coord><x>2</x><y>3</y></coord>
</data>
<data id="second">
<coord><x>3</x><y>2</y></coord>
<coord><x>4</x><y>1</y></coord>
<coord><x>5</x><y>0</y></coord>
</data>
</alldata>
I would like to format this data in three columns "id", "x", and "y" to get:
first;0;5
first;1;4
first;2;3
second;3;2
second;4;1
second;5;0
My attempts with XMLstarlet has failed indicating that I don't really understand what I am doing.
xml sel -T -t -m /alldata/data -v "#id" -m /alldata/data/coord -v "concat(x,';',y)" -n mydata.xml
gives me:
first0;5
1;4
2;3
3;2
4;1
5;0
second0;5
1;4
2;3
3;2
4;1
5;0
which is not what I want or expected. Is it possible to modify my query to get the desired output?

-m /alldata/data -v "#id" -m /alldata/data/coord -v "concat(x,';',y)"
The main problem is the -m /alldata/data/coord: this matches all the coord elements in the entire document, what you really wanted was just the coord under the current data elements:
-m /alldata/data -v "#id" -m coord -v "concat(x,';',y)"
You also want the id on every line so you need to move into the inner loop:
-m /alldata/data -m coord -v "concat(../#id,';',x,';',y)"
At this point there is no benefit to having 2 nested loops so we can simplify:
xml sel -T -t -m /alldata/data/coord -v "concat(../#id,';',x,';',y)" -n mydata.xml

Related

Is any way serah match value from root node by xmlstarlet and return XPATH

As title
I am resarch xmlstartle, but seems no way to serach value from root node then return XPATH
Is any idea?
ThanksPeter
Perhaps you can make use of this example which handles elements and
attributes but not other node types. Assuming a POSIX shell,
indentation and line continuation characters added for readability.
xmlstarlet select --text -t \
-m '//xsl:*/#test[contains(.,"position")]' \
-m 'ancestor-or-self::*' \
--var pos='1+count(preceding-sibling::*[name() = name(current())])' \
-v 'concat("/",name(),"[",$pos,"]")' \
-b \
--if 'count(. | ../#*) = count(../#*)' \
-v 'concat("/#",name())' \
-b \
-n \
/usr/share/*/xslt/docbook/common/db-common.xsl
Where:
the outer -m (--match) option specifies the target, with optional
search conditions given as
predicates
the inner -m (--match) builds the XPath of elements from root to target,
calculating position by counting siblings
for an attribute node target - which doesn't match ancestor-or-self::* -
the -i (--if) clause adjusts the XPath
a -C (--comp) option before -t lists the generated XSLT code
Output:
/xsl:stylesheet[1]/xsl:template[2]/xsl:for-each[1]/xsl:if[1]/#test
/xsl:stylesheet[1]/xsl:template[3]/xsl:for-each[1]/xsl:if[1]/#test
/xsl:stylesheet[1]/xsl:template[7]/xsl:for-each[1]/xsl:choose[1]/xsl:when[1]/#test
/xsl:stylesheet[1]/xsl:template[7]/xsl:for-each[1]/xsl:choose[1]/xsl:when[3]/#test
Output from outer -m '//xsl:param[string(#select)]':
/xsl:stylesheet[1]/xsl:template[1]/xsl:param[1]
/xsl:stylesheet[1]/xsl:template[4]/xsl:param[1]
/xsl:stylesheet[1]/xsl:template[5]/xsl:param[1]
/xsl:stylesheet[1]/xsl:template[5]/xsl:param[2]
/xsl:stylesheet[1]/xsl:template[6]/xsl:param[1]

What is the easiest way for grepping the 'man grep' for flags

I do use grep a lot, but I would love to improve a bit.
Regarding the question. I wanted to narrow the man entry to find the explanation of what the -v in grep -v 'pattern' filename stood for, mainly this:
-v, --invert-match
Selected lines are those not matching any of the specified patterns.
Thus, to find the next five lines after the line which contains -v I tried:
man grep | grep -A 5 -v
and
man grep | grep -A 5 '-v'
but they return:
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
[-e pattern] [-f file] [--binary-files=value] [--color=when]
[--context[=num]] [--directories=action] [--label] [--line-buffered]
[--null] [pattern] [file ...]
This confuses me since:
man grep | grep -A 5 'Selected'
and
man grep | grep -A 5 Selected
do work.
What is wrong in my approach? Is there any easier way to achieve what I need?
One approach is to parse the Info documents for the command directly. If you run info grep (or other command) you will often find much more detailed and better-structured documentation, which will let you pin-point just the section you need.
Here's a function that will print out the relevant Info section for an option/variable/etc:
info_search() {
info --subnodes "$1" -o - 2>&- \
| awk -v RS='' "/(^|\n)(‘|'|\`)$2((,|\[| ).*)?(’|')\n/"
}
This should work on Linux/macOS/BSD. Output is like:
$ info_search grep -v
‘-v’
‘--invert-match’
Invert the sense of matching, to select non-matching lines. (‘-v’
is specified by POSIX.)
$ info_search gawk RS
'RS == "\n"'
Records are separated by the newline character ('\n'). In effect,
every line in the data file is a separate record, including blank
...
$ info_search bash -i
`-i'
Force the shell to run interactively. Interactive shells are
...

Read hex data into less

I want to give a big data file to less -s -M +Gg such that read current given data in less -s -M +Gg.
While-loop example (see ntc2's answer)
Less command explained here.
Replacing the yes by a binary file which is converted to binary ascii and hex:
while read -u 10 p || [[ -n $p ]]; do
hexdump -e '/4 "%08x\n"' {$p} \
\
| less -s -M +Gg
done 10</Users/masi/Dropbox/7-8\:2015/r3.raw
where the looping is based on this thread here.
How can you read such data into less?
I don't understand the details of the example, but I think you want to put the less outside of the loop, like this:
while read -u 10 p || [[ -n $p ]]; do
hexdump -e '/4 "%08x\n"' {$p}
done 10</Users/masi/Dropbox/7-8\:2015/r3.raw | less -s -M +Gg

extracting nodes values with xmlstarlet

i have this xml schema , what i want is how to extract the values of all the nodes one by one, using XMLStarlet , in shell script
<service>
<imageScroll>
<imageName>Photo_Gallerie_1.jpg</imageName>
</imageScroll>
<imageScroll>
<imageName>Photo_Gallerie_2.jpg</imageName>
</imageScroll>
<imageScroll>
<imageName>Photo_Gallerie_3.jpg</imageName>
</imageScroll>
</service>
xmlstarlet sel -t -m "//imageName" -v . -n your.xml
output:
Photo_Gallerie_1.jpg
Photo_Gallerie_2.jpg
Photo_Gallerie_3.jpg
Is that what you needed?
sel (select mode)
-t (output template(this is pretty much required)
-m (for each match of the following value)
"// (the double slash means it could be anywhere in the tree)
imageName (name of node you want)"
-v (requests the value of an element in the current path) and the . represents current element in iteration (you could put the name of the node there but it's generally easier this way)
and then the
-n is to add a line for every value you match.
that was the solution that i found and it did perfectly the job.
imagescroller=`xmlstarlet sel -t -m "//root/services/service/imageScroll[rank_of_the_desired_item]" -v imageName -n myfile.xml
sorry for late.

using grep to parse output from another command

after doing the command in the terminal: forever list
i get the following output:
info: Forever processes running
data: uid command script forever pid logfile uptime
data: [0] 0ClV node enfomo-server.js 376 377 /Users/USERNAME/.forever/0ClV.log 0:0:37:26.987
i need to use grep or some alternative to give as output the following string only:
/Users/USERNAME/.forever/0ClV.log
what is the proper command?
You can do this with grep using the -o flag which only prints the matching part:
forever list | grep -o '\/Users.*log'
First you might want to isolate only the lines you want with grep, then awk would work:
grep node file | awk '{print $7}'
or cut:
grep node file | cut -d\ -f7

Resources