<p>Sometimes I need to quickly extract some arbitrary data from XML files to put into a CSV format. What's your best practices for doing this in the Unix terminal? I would love some code examples, so for instance how can I get the following problem solved?</p>
<p>Example XML input:</p>
<pre class="lang-html prettyprint-override"><code>&lt;root&gt;
    &lt;myel name=&quot;Foo&quot; /&gt;
    &lt;myel name=&quot;Bar&quot; /&gt;
&lt;/root&gt;
</code></pre>
<p>My desired CSV output:</p>
<pre><code>Foo,
Bar,
</code></pre>

[{'answer_id': 29023, 'author': 'Peter Hilton', 'author_id': 2670, 'author_profile': 'https://Stackoverflow.com/users/2670', 'pm_score': 3, 'selected': False, 'text': '<p>Use a command-line XSLT processor such as <a href="http://xmlsoft.org/XSLT/xsltproc2.html" rel="noreferrer">xsltproc</a>, <a href="http://saxon.sourceforge.net/" rel="noreferrer">saxon</a> or <a href="http://xalan.apache.org/" rel="noreferrer">xalan</a> to parse the XML and generate CSV. Here\'s <a href="http://www.stylusstudio.com/xmldev/200404/post60210.html" rel="noreferrer">an example</a>, which for your case is the stylesheet:</p>\n\n<pre><code>&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;\n&lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;\n    &lt;xsl:output method="text"/&gt;\n\n    &lt;xsl:template match="root"&gt;\n        &lt;xsl:apply-templates select="myel"/&gt;\n    &lt;/xsl:template&gt;\n\n    &lt;xsl:template match="myel"&gt;\n        &lt;xsl:for-each select="@*"&gt;\n            &lt;xsl:value-of select="."/&gt;\n            &lt;xsl:value-of select="\',\'"/&gt;\n        &lt;/xsl:for-each&gt;\n        &lt;xsl:text&gt;&amp;#10;&lt;/xsl:text&gt;\n    &lt;/xsl:template&gt; \n&lt;/xsl:stylesheet&gt;\n</code></pre>\n'}, {'answer_id': 29032, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 4, 'selected': True, 'text': '<p>If you just want the name attributes of any element, here is a quick but incomplete solution.</p>\n\n<p>(Your example text is in the file <em>example</em>)</p>\n\n<blockquote>\n  <p>grep "name" example | cut -d"\\"" -f2,2\n  | xargs -I{} echo "{},"</p>\n</blockquote>\n'}, {'answer_id': 29602, 'author': 'jelovirt', 'author_id': 2679, 'author_profile': 'https://Stackoverflow.com/users/2679', 'pm_score': 4, 'selected': False, 'text': '<p><a href="https://stackoverflow.com/questions/29004/parsing-xml-using-unix-terminal#29023">Peter\'s answer</a> is correct, but it outputs a trailing line feed.</p>\n\n<pre><code>&lt;xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"&gt;\n  &lt;xsl:output method="text"/&gt;\n  &lt;xsl:template match="root"&gt;\n    &lt;xsl:for-each select="myel"&gt;\n      &lt;xsl:value-of select="@name"/&gt;\n      &lt;xsl:text&gt;,&lt;/xsl:text&gt;\n      &lt;xsl:if test="not(position() = last())"&gt;\n        &lt;xsl:text&gt;&amp;#xA;&lt;/xsl:text&gt;\n      &lt;/xsl:if&gt;\n    &lt;/xsl:for-each&gt;\n  &lt;/xsl:template&gt;\n&lt;/xsl:stylesheet&gt;\n</code></pre>\n\n<p>Just run e.g.</p>\n\n<pre><code>xsltproc stylesheet.xsl source.xml\n</code></pre>\n\n<p>to generate the CSV results into standard output.</p>\n'}, {'answer_id': 29670, 'author': 'AndrewR', 'author_id': 2994, 'author_profile': 'https://Stackoverflow.com/users/2994', 'pm_score': 2, 'selected': False, 'text': '<p>Here\'s a little ruby script that does <em>exactly</em> what your question asks (pull an attribute called \'name\' out of elements called \'myel\'). Should be easy to generalize</p>\n\n<pre><code>#!/usr/bin/ruby -w\n\nrequire \'rexml/document\'\n\nxml = REXML::Document.new(File.open(ARGV[0].to_s))\nxml.elements.each("//myel") { |el| puts "#{el.attributes[\'name\']}," if el.attributes[\'name\'] }\n</code></pre>\n'}, {'answer_id': 58479, 'author': 'DaveP', 'author_id': 3577, 'author_profile': 'https://Stackoverflow.com/users/3577', 'pm_score': 3, 'selected': False, 'text': '<p>XMLStarlet is a command line toolkit to query/edit/check/transform\nXML documents (for more information, see <a href="http://xmlstar.sourceforge.net/" rel="nofollow noreferrer">XMLStarlet Command Line XML Toolkit</a>)</p>\n<p>No files to write, just pipe your file to xmlstarlet and apply an xpath filter.</p>\n<pre><code>cat file.xml | xml sel -t -m \'xpathExpression\' -v \'elemName\' \'literal\' -v \'elname\' -n\n</code></pre>\n<p>-m expression\n-v value\n\'\' included literal\n-n newline</p>\n<p>So for your xpath the xpath expression would be //myel/@name\nwhich would provide the two attribute values.</p>\n<p>Very handy tool.</p>\n'}, {'answer_id': 90983, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 1, 'selected': False, 'text': '<p>your test file is in test.xml.</p>\n\n<pre><code>sed -n \'s/^\\s`*`&amp;lt;myel\\s`*`name="\\([^"]`*`\\)".`*`$/\\1,/p\' test.xml\n</code></pre>\n\n<p>It has it\'s pitfalls, for example if it is not strictly given that each <strong>myel</strong> is on one line you have to "normalize" the xml file first (so each <strong>myel</strong> is on one separate line)<br /></p>\n'}, {'answer_id': 21250512, 'author': 'Uday Thombre', 'author_id': 3217934, 'author_profile': 'https://Stackoverflow.com/users/3217934', 'pm_score': 1, 'selected': False, 'text': '<p>Answering the original question, assuming xml file is &quot;test.xml&quot; that contains:</p>\n<pre class="lang-xml prettyprint-override"><code>&lt;root&gt;\n&lt;myel name=&quot;Foo&quot; /&gt;\n&lt;myel name=&quot;Bar&quot; /&gt;\n&lt;/root&gt;\n</code></pre>\n<pre><code>cat text.xml | tr -s &quot;\\&quot;&quot; &quot; &quot; | awk \'{printf &quot;%s,\\n&quot;, $3}\'\n</code></pre>\n'}, {'answer_id': 64622701, 'author': 'Reino', 'author_id': 2703456, 'author_profile': 'https://Stackoverflow.com/users/2703456', 'pm_score': 1, 'selected': False, 'text': '<p>Using <a href="/questions/tagged/xidel" class="post-tag" title="show questions tagged &#39;xidel&#39;" rel="tag">xidel</a>:</p>\n<pre><code>xidel -s input.xml -e \'//myel/concat(@name,&quot;,&quot;)\'\n</code></pre>\n'}, {'answer_id': 74336359, 'author': 'jpseng', 'author_id': 16332641, 'author_profile': 'https://Stackoverflow.com/users/16332641', 'pm_score': 0, 'selected': False, 'text': '<p><a href="https://mikefarah.gitbook.io/yq/" rel="nofollow noreferrer">yq</a> can be used for XML parsing.</p>\n<p>It is a lightweight and portable command-line YAML processor and can also deal with XML.\nThe syntax is similar to <a href="https://stedolan.github.io/jq/" rel="nofollow noreferrer">jq</a></p>\n<p><strong>Input</strong></p>\n<pre><code>&lt;root&gt;\n  &lt;myel name=&quot;Foo&quot; /&gt;\n  &lt;myel name=&quot;Bar&quot;&gt;\n    &lt;mysubel&gt;stairway to heaven&lt;/mysubel&gt;\n  &lt;/myel&gt;\n&lt;/root&gt;\n</code></pre>\n<p><strong>usage example 1</strong></p>\n<p><code>yq e \'.root.myel.0.+name\' $INPUT</code> (version &gt;= 4.30: <code>yq e \'.root.myel.0.+@name\' $INPUT</code>)</p>\n<pre><code>Foo\n</code></pre>\n<p><strong>usage example 2</strong></p>\n<p><code>yq</code> has a nice builtin feature to make XML easily grep-able</p>\n<p><code>yq --input-format xml --output-format props $INPUT</code></p>\n<pre><code>root.myel.0.+name = Foo\nroot.myel.1.+name = Bar\nroot.myel.1.mysubel = stairway to heaven\n</code></pre>\n<p><strong>usage example 3</strong></p>\n<p><code>yq</code> can also convert an XML input into JSON or YAML</p>\n<p><code>yq --input-format xml --output-format json $INPUT</code></p>\n<pre class="lang-json prettyprint-override"><code>{\n  &quot;root&quot;: {\n    &quot;myel&quot;: [\n      {\n        &quot;+name&quot;: &quot;Foo&quot;\n      },\n      {\n        &quot;+name&quot;: &quot;Bar&quot;,\n        &quot;mysubel&quot;: &quot;stairway to heaven&quot;\n      }\n    ]\n  }\n}\n</code></pre>\n<p><code>yq --input-format xml $FILE</code> (<code>YAML</code> is the default format)</p>\n<pre class="lang-yaml prettyprint-override"><code>root:\n  myel:\n    - +name: Foo\n    - +name: Bar\n      mysubel: stairway to heaven\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/29004', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/261/']