I have a document containing a list of files. What is simple way to extract filenames inside the href element (without quotes)and copy them into the list separated by line breaks?

<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>
<item id="css" href="845214570.css" media-type="text/css"/>
<item id="cover-image" href="845214570.jpg" media-type="image/jpeg"/>
<item id="nav" href="nav.xhtml" media-type="application/xhtml+xml" properties="nav"/>
<item id="cover" href="cover.xhtml" media-type="application/xhtml+xml"/>
<item id="author" href="author.xhtml" media-type="application/xhtml+xml"/>
<item id="title" href="title.xhtml" media-type="application/xhtml+xml"/>
<item id="copy" href="copy.xhtml" media-type="application/xhtml+xml"/>
<item id="contents" href="contents.xhtml" media-type="application/xhtml+xml"/>
<item id="preface" href="preface.xhtml" media-type="application/xhtml+xml"/>
<item id="ack" href="ack.xhtml" media-type="application/xhtml+xml"/>
<item id="ch1" href="ch1.xhtml" media-type="application/xhtml+xml"/>
<item id="ch2" href="ch2.xhtml" media-type="application/xhtml+xml"/>
<item id="ch3" href="ch3.xhtml" media-type="application/xhtml+xml"/>
<item id="ch4" href="ch4.xhtml" media-type="application/xhtml+xml"/>
<item id="ch5" href="ch5.xhtml" media-type="application/xhtml+xml"/>
<item id="ch6" href="ch6.xhtml" media-type="application/xhtml+xml"/>
<item id="ch7" href="ch7.xhtml" media-type="application/xhtml+xml"/>
<item id="ch8" href="ch8.xhtml" media-type="application/xhtml+xml"/>
<item id="ch9" href="ch9.xhtml" media-type="application/xhtml+xml"/>
<item id="ch10" href="ch10.xhtml" media-type="application/xhtml+xml"/>
<item id="ch11" href="ch11.xhtml" media-type="application/xhtml+xml"/>
<item id="app" href="app.xhtml" media-type="application/xhtml+xml"/>
<item id="appb" href="appb.xhtml" media-type="application/xhtml+xml"/>
<item id="appc" href="appc.xhtml" media-type="application/xhtml+xml"/>
<item id="index" href="index.xhtml" media-type="application/xhtml+xml"/>
<item id="img-f0019-01" href="f0019-01.jpg" media-type="image/jpeg"/>
<item id="img-f0027-01" href="f0027-01.jpg" media-type="image/jpeg"/>
<item id="img-f0029-01" href="f0029-01.jpg" media-type="image/jpeg"/>

For an XML file with this simple format, you can use grep:

grep -Po 'href="\K[^"]*' file.xml > filenames.lst

However, if you had a more complex xml, you could and should prefer a proper xml parser, e.g. xmlstarlet:

xmlstarlet sel -t -v '//item/@href' -n file.xml > filenames.lst

This can be installed via

sudo apt install xmlstarlet

As you have tagged your question with python, of course you can also use that:

#!/usr/bin/env python3
import xml.etree.ElementTree as ET
root = ET.parse('file.xml')
for item in root.findall('.//item'):
  • The grep works just fine. Thank you.
    – minto
    Sep 21 at 15:00
  • for python(I have python 2.x), it show error ./extract.py ./extract.py:4: FutureWarning: This search is broken in 1.3 and earlier, and will be fixed in a future version. If you rely on the current behaviour, change it to './/item' for item in root.findall('//item'): I changed, but no any output printed.
    – minto
    Sep 21 at 15:12
  • I changed that to be compatible with older version of python.
    – pLumo
    Sep 21 at 15:16
  • Another option I discovered recently is xq from the yq suite which enables JSON-like queries on xml documents ex. xq -r '.manifest.item[] | ."@href"' file.xml Sep 21 at 16:18
  • ...or hxselect -s \\n -c 'item::attr(href)' < file.xml from the html-xml-utils package.
    – bac0n
    Sep 21 at 19:50

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.