Curl GET XML Example

Fetching XML is a GET with an Accept header. The work is on the receiving end: making the document readable, extracting one value from it, and noticing when what came back is not XML at all.

Last updated . How this page is checked.

The command

curl -H "Accept: application/xml" https://httpbin.org/xml

Opens the request console with this request filled in. It is sent from api-tester.com's server rather than from your machine, so it shows what the endpoint returns, not how your own network or curl build behaves.

What the flags do

FlagWhat it does
-H "Accept: application/xml"Ask for XML. Feeds may want application/rss+xml or application/atom+xml.
-sNo progress meter, so the output can go straight into a parser.
--compressedAccept gzip and decompress it. Sitemaps and feeds are often served compressed.
-o file.xmlSave the document instead of printing it.

Formatting and querying the response

Servers send XML on a single line or with whatever indentation their serialiser produced. xmllint --format re-indents it. The same tool evaluates XPath, which is the dependable way to take one value out of a document: wrap the path in string() for text, or count() for a number of elements. The trailing dash tells xmllint to read from the pipe.

curl -s -H "Accept: application/xml" https://httpbin.org/xml | xmllint --format -
curl -s https://httpbin.org/xml | xmllint --xpath "string(//slide[1]/title)" -
curl -s https://httpbin.org/xml | xmllint --xpath "count(//slide)" -

Sitemaps, feeds and namespaces

The XML most people fetch is not from an API at all: it is a sitemap, an RSS or Atom feed, or a configuration document. Many of these declare a default namespace on the root element, and an XPath such as //loc then matches nothing, because the element's full name includes that namespace. Matching on local-name() sidesteps it without having to register a prefix.

curl -s --compressed https://example.com/sitemap.xml \
  | xmllint --xpath "//*[local-name()='loc']/text()" -

curl -s -H "Accept: application/rss+xml" https://example.com/feed \
  | xmllint --xpath "//item/title/text()" -

Checking what actually came back

Accept is a preference, and a server is free to ignore it. Before parsing, look at the status code and the response's own Content-Type; both are available as write-out variables while the body goes to a file. Saving to a file also helps with character sets: curl does not convert encodings, so a document declared as ISO-8859-1 looks garbled in a UTF-8 terminal yet is read correctly by a parser that honours the XML declaration.

curl -s -o feed.xml -w "%{http_code} %{content_type}\n" \
  -H "Accept: application/xml" https://httpbin.org/xml

Common mistakes

  • An XPath that returns nothing usually means a namespace. Elements in a default namespace are not matched by their bare names.
  • An HTML error page is not XML. A 404 or a login redirect fed to a parser produces a parse error far from the real cause.
  • Avoid grep and sed for anything beyond a quick look. Attribute order, line breaks and entity encoding all vary between equivalent documents.

Related curl examples

More under Request bodies

References

  • curl man page: -H — Adding a request header such as Accept.
  • MDN: XPath — The query language used to pull values out of an XML document.

These links leave api-tester.com, which is independent of the projects they point to.

FAQ

How do I get XML with curl?

Send a GET request with an Accept header for XML: curl -H "Accept: application/xml" URL. The XML response body is printed to the terminal.

How do I pretty-print XML from curl?

Pipe the output to xmllint: curl -s URL | xmllint --format - indents the document so it is readable.

How do I extract a value from an XML response on the command line?

Pipe curl into xmllint with an XPath expression, for example curl -s URL | xmllint --xpath "string(//title)" - to print the text of the first title element.