Во-первых, мой ответ предполагает, что у вас есть действительно правильно сформированный исходный XML.Предоставленный вами пример кода не является XML, так как он не имеет открываемого корневого элемента, а именно <Context>
- но я все равно предположу, что он есть.
Bashфункции сами по себе не очень хорошо подходят для разбора XML
В этом Bash FAQ указано следующее:
Не пытаться [извлечь данные из файла XML] с помощью sed , awk , grep и т. д. (это приводит к нежелательным результатам )
Если необходимо использоватьЗатем сценарий оболочки использует специальный инструмент командной строки для XML, такой как XMLStarlet (есть и другие подобные инструменты).См. Информацию о загрузке здесь - если у вас еще не установлен XML Starlet.
Решение:
Используя XML Starlet, вы можете запустить следующие команды:
uname=$(xml sel -t -v "/Context/Resource/@username" path/to/file.xml)
pword=$(xml sel -t -v "/Context/Resource/@password" path/to/file.xml)
echo "$uname $pword" # --> demo test
Пояснение
uname=$(...)
Здесь мы используем Подстановка команд назначить вывод команды XML Startlet переменной с именем uname
(т. е. имя пользователя).
xml sel -t -v "/Context/Resource/@username"
ThisКоманда разбивается следующим образом:
xml
- вызвать команду XML Starlet. sel
- выбрать данные илизапросить XML-документ (ы). -t
- опция шаблона. -v
- вывести значение выражения XPATH. "/Context/Resource/@username"
- выражение xpath для выбора значения атрибута username
тега / элемента Resource
.
path/to/file.xml
Эта часть должна быть замененаced с реальным путем к вашему файлу .xml
.
Аналогично, мы используем аналогичную команду для получения значения атрибута password
, посредством чего мы назначаем вывод командыв переменную с именем pword
и измените выражение XPATH.
Редактировать 1: более эффективная команда
Согласно Чарльз Даффи * первый комментарий ниже ... вы также можете более эффективно извлечь оба значения атрибута, используя следующую команду:
{ IFS= read -r uname && IFS= read -r pword; } < <(xml sel -t -v "/Context/Resource/@username" -n -v "/Context/Resource/@password" path/to/file.xml)
echo "$uname $pword" # --> demo test
Основное преимущество заключается в том, что исходный XML-файл читается только один раз.
Редактировать 2: Использование XML Starlet для генерации шаблона XSLT, который затем можно запустить в любой системе с xsltproc
, включая хосты, на которых не установлен XML Starlet:
Согласно Charles DuffyВторой комментарий ниже ...
Также возможно использовать XML Starlet для генерации шаблона xslt , который получен из запроса XML Starlet, показанного ранее.Созданный файл .xsl
может быть запущен в любой системе, в которой есть xsltproc (включая хосты, на которых не установлен XML Starlet).
Следующие шаги демонстрируют, как этого добиться:
Сначала выполните следующую команду XML Starlet для создания файла .xsl
:
xml sel -C -t -v "/Context/Resource/@username" -n -v "/Context/Resource/@password" path/to/file.xml > path/to/resultant/my-template.xsl
Эта команда очень похожа на ранее показанную команду XML Starlet.Существенные различия:
- Дополнительная опция
-C
между sel
и -t
Оператор перенаправления >
ипуть к файлу.Здесь указывается место, в котором следует сохранить выходные данные (т. Е. Сгенерированный шаблон / таблица стилей XSLT).
Примечание необходимо изменить часть path/to/resultant/my-template.xsl
при необходимости.
Содержимое сгенерированной таблицы стилей XSLT будет выглядеть примерно так:
my-template.xsl
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="/Context/Resource/@username"/>
</xsl:call-template>
<xsl:value-of select="' '"/>
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="/Context/Resource/@password"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Далее выполните следующую команду, которая использует xsltproc для преобразованияисходный файл .xml
.Это в конечном итоге присваивает результат преобразования двум переменным, то есть uname
и pword
:
{ IFS= read -r uname && IFS= read -r pword; } < <(xsltproc path/to/resultant/my-template.xsl path/to/file.xml)
echo "$uname $pword" # --> demo test
Примечание детали, обозначенные path/to/resultant/my-template.xsl
и path/to/file.xml
, должны быть при необходимости изменены.