Синтаксический анализ XML с помощью терминала unix
Вопрос
Иногда мне нужно быстро извлечь некоторые произвольные данные из XML-файлов, чтобы перевести их в формат CSV.Каковы ваши наилучшие методы для выполнения этого в терминале Unix?Мне бы хотелось привести несколько примеров кода, например, как я могу решить следующую проблему?
Пример ввода XML:
<root>
<myel name="Foo" />
<myel name="Bar" />
</root>
Мой желаемый результат в формате CSV:
Foo,
Bar,
Решение
Если вам просто нужны атрибуты name любого элемента, вот быстрое, но неполное решение.
(Ваш пример текста находится в файле пример)
пример grep "name" | вырезать -d"\"" -f2,2 | xargs -I{} echo "{},"
Другие советы
Ответ Питера является правильным, но он выводит перевод строки в конце.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:template match="root">
<xsl:for-each select="myel">
<xsl:value-of select="@name"/>
<xsl:text>,</xsl:text>
<xsl:if test="not(position() = last())">
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Просто запустите, например
xsltproc stylesheet.xsl source.xml
сгенерировать результаты CSV в стандартный вывод.
Используйте XSLT-процессор командной строки, такой как xsltproc, саксонец или ксалан чтобы проанализировать XML и сгенерировать CSV.Вот пример, что в вашем случае является таблицей стилей:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="root">
<xsl:apply-templates select="myel"/>
</xsl:template>
<xsl:template match="myel">
<xsl:for-each select="@*">
<xsl:value-of select="."/>
<xsl:value-of select="','"/>
</xsl:for-each>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
XMLStarlet - это набор инструментов командной строки для запроса / редактирования / проверки / преобразования XML-документов (для получения дополнительной информации см. http://xmlstar.sourceforge.net/)
Никаких файлов для записи, просто передайте ваш файл в xmlstarlet и примените фильтр xpath.
cat file.xml | xml sel -t -m 'xpathExpression' -v 'elemName' 'literal' -v 'elname' -n
-m выражение -v значение " включенный литерал -n перевод строки
Таким образом, для вашего xpath выражением xpath было бы //myel/@name , которое предоставляло бы два значения атрибута.
Очень удобный инструмент.
Вот небольшой ruby-скрипт, который делает именно так что задается в вашем вопросе (извлеките атрибут с именем 'name' из элементов с именем 'myel').Должно быть легко обобщить
#!/usr/bin/ruby -w
require 'rexml/document'
xml = REXML::Document.new(File.open(ARGV[0].to_s))
xml.elements.each("//myel") { |el| puts "#{el.attributes['name']}," if el.attributes['name'] }
Отвечая на исходный вопрос, предполагая, что XML-файл "test.xml" содержит:
<root>
<myel name="Foo" />
<myel name="Bar" />
</root>
cat text.xml | tr -s "\"" " " | awk '{printf "%s,\n", $3}'
ваш тестовый файл находится в test.xml.
sed -n 's/^\s`*`<myel\s`*`name="\([^"]`*`\)".`*`$/\1,/p' test.xml
В этом есть свои подводные камни, например, если строго не указано, что каждый миэль находится в одной строке, вы должны сначала "нормализовать" xml-файл (так что каждый миэль находится на одной отдельной строке)