1

I'm trying to answer a question. It involves using the command recode. A specific line has to be parsed by the command leaving the rest untouched. The file is an xml file. Example:

    <ITEM_ID>foo</ITEM_ID>
    <PRODUCTNAME>bar</PRODUCTNAME>
    <DESCRIPTION><p>foo</p><p> </p><p> </p></DESCRIPTION>
    <URL>bar</URL>
    <IMGURL>foo</IMGURL>
    <IMGURL_ALTERNATIVE></IMGURL_ALTERNATIVE>

The desired output should be:

    <ITEM_ID>foo</ITEM_ID>
    <PRODUCTNAME>bar</PRODUCTNAME>
    <DESCRIPTION>&lt;p&gt;foo&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;</DESCRIPTION>
    <URL>bar</URL>
    <IMGURL>foo</IMGURL>
    <IMGURL_ALTERNATIVE></IMGURL_ALTERNATIVE>


NOTE: The command recode works as intended. Avoiding the conversion of the tags DESCRIPTION can be solved later, is not part of the question.

The line that should be changed is the one that starts with <DESCRIPTION>.

I'm really bad at awk still, the intended command would be something like this:

awk '/<DESCRIPTION>/ { $0 = print $0 "| recode ..html" }1' foo.txt

which of course doesn't work.

How should I accomplish this?

7
  • 1
    What is that awk command supposed to be doing? Are you trying to pass the first field through recode? The entire line? A file? How would you do this with echo string |recode if you didn't need to use awk? – terdon Feb 5 at 17:21
  • @terdon The entire line. With echo would be echo "<DESCRIPTION><p>foo</p><p> </p><p> </p></DESCRIPTION>" | recode ..html, which output would be: &lt;DESCRIPTION&gt;&lt;p&gt;foo&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;/DESCRIPTION&gt;. – schrodigerscatcuriosity Feb 5 at 17:39
  • @terdon the command I put as example is a very ugly representation of what I'm trying to accompĺish, awk is still a mistery to me, in fact is almost gibberish, I'm trying so many things... – schrodigerscatcuriosity Feb 5 at 17:41
  • That's what's confusing me. If I run echo "<DESCRIPTION><p>foo</p><p> </p><p> </p></DESCRIPTION>" | recode ..html, I get something completely and utterly different (it converts to html codes for chinese characters) than what you show. I can give you the awk command for it, but it doesn't seem to be what you need at all. – terdon Feb 5 at 17:45
  • @terdon Mmh, there's something there the with depending on the locale. OP of the original question (askubuntu) run mi firts attemtp (without awk), using recode, and did'nt had this charset/locale problem. If you want to pass the command, maybe will shed some light. – schrodigerscatcuriosity Feb 5 at 17:49
2

You need to use awk's getline to read the output into a variable. You also need to set the locale correctly for the recoding to work as expected. Try this:

$ LC_ALL=C gawk '/DESCRIPTION/{
        "echo \""$0"\" | recode ..html" | getline ff; print ff
       }' file 
    &lt;DESCRIPTION&gt;&lt;p&gt;foo&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;/DESCRIPTION&gt;
7
  • For the command to be compĺete, to print the whole file, you need to add the }1, although it prints the DESCRIPTION twice, one parsed and the other not. The output desired is the whole file, and the selected line changed. – schrodigerscatcuriosity Feb 5 at 18:02
  • 1
    @schrodigerscatcuriosity that wasn't part of the question. I am just showing how to pass an awk variable to a shell command and then retrieve the output and use it in awk. Adding }1wouldn't be enough anyway, you would want something like: awk '/DESCRIPTION/{"echo \""$0"\" | recode ..html" | getline $0;}1' file which would save the output to $0 and then allow you to print it normally. – terdon Feb 5 at 18:18
  • You seem to encode the entire DESCRIPTION node, not just its value. – Kusalananda Feb 5 at 18:48
  • Save the shell command in a variable so you can close it after every line processed otherwise YMMV with trying to read the command output 1 line at a time. You should also protect the call to getline so it doesn't silently reprint the previously successful value on a failure and you should be using single quotes, not double, around the $0 in the echo command being given to shell. – Ed Morton Feb 5 at 18:54
  • @Kusalananda yes, because that's what the question asked for: "NOTE: The command recode works as intended. Avoiding the conversion of the tags DESCRIPTION can be solved later, is not part of the question.". – terdon Feb 5 at 18:55
2

Assuming that the document is well formed, with some root node root...

$ cat file.xml
<root>
    <ITEM_ID>foo</ITEM_ID>
    <PRODUCTNAME>bar</PRODUCTNAME>
    <DESCRIPTION><p>foo</p><p> </p><p> </p></DESCRIPTION>
    <URL>bar</URL>
    <IMGURL>foo</IMGURL>
    <IMGURL_ALTERNATIVE></IMGURL_ALTERNATIVE>
</root>

Then,

$ xmlstarlet ed -u '/root/DESCRIPTION' -v "$( xmlstarlet sel -t -c '/root/DESCRIPTION/*' file.xml )" file.xml
<?xml version="1.0"?>
<root>
  <ITEM_ID>foo</ITEM_ID>
  <PRODUCTNAME>bar</PRODUCTNAME>
  <DESCRIPTION>&lt;p&gt;foo&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;</DESCRIPTION>
  <URL>bar</URL>
  <IMGURL>foo</IMGURL>
  <IMGURL_ALTERNATIVE/>
</root>

What's happening here is that xmlstarlet sel is used to extract the a copy of the nodes under the /root/DESCRIPTION node. This is what xmlstarlet sel -t -c '/root/DESCRIPTION/*' file.xml does, and it returns the string <p>foo</p><p> </p><p> </p>.

This string is then used as the new text value for the /root/DESCRIPTION node by means of an xmlstarlet ed command. The new value is had from a command substitution.

Note that the value is automatically XML encoded.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.