Как преобразовать атрибуты из XML в значения и значения в подзначения ...? - PullRequest
1 голос
/ 01 мая 2011

вот что я хотел бы сделать:

Преобразовать этот XML:

<book author="Name" year="2000">Book title</book>

В этот XML:

<book><author>Name</author><year>2000</year><value>Book title</value></book>

Я хотел бы сделать этос помощью xslt или чего-то еще, что я могу запустить из bash ...

Спасибо.

Ответы [ 2 ]

4 голосов
/ 01 мая 2011

Это преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:element name="{name()}">
    <xsl:value-of select="."/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="text()">
  <value>
   <xsl:value-of select="."/>
  </value>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному документу XML :

<book author="Name" year="2000">Book title</book>

дает желаемый, правильный результат:

<book><author>Name</author><year>2000</year><value>Book title</value></book>

Объяснение

  1. Правило / шаблон копирует каждый узел "как есть".

  2. Мы заменяем правило идентификации шаблоном, соответствующим любому атрибуту. Он создает элемент, имя которого является именем соответствующего атрибута, а единственный дочерний элемент текстового узла является значением соответствующего атрибута.

  3. Наконец, мы переопределяем правило идентификации шаблоном, который соответствует любому текстовому узлу. Он просто выводит этот узел, завернутый в value родительский элемент.

Примечание. 1040 *: Использование и переопределение правила идентификации является наиболее фундаментальным и мощным шаблоном проектирования XSLT.

Я бы хотел сделать это с помощью xslt или что-то, что я могу запустить из Баш ...

Большинство процессоров XSLT поставляются с утилитой командной строки , которая вызывает преобразование XSLT из командной строки. Прочитайте документацию вашего процессора XSLT.

0 голосов
/ 02 мая 2011

Вот решение с использованием xmlstarlet & Bash (хотя оно не сохраняет значение тега author-year-subvalue):

(
i=0
xmlstr='<book author="Name" year="2000">Book title</book>'

while IFS="" read -r -d $'\n' xpath; do 
  ((i+=1))
  name="$(printf '%s' "$xmlstr" | xmlstarlet sel -T -t -m "/${xpath}" -v "name(.)")" 
  value="$(printf '%s' "$xmlstr" | xmlstarlet sel -T -t -m "/${xpath}" -v '.')" 
  if [[ $i -eq 1 ]] || [[ "${xpath%/*}" != "${rootxpath}" ]]; then
    rootxpath="${xpath%/*}"
    subvalue="$(printf '%s' "$xmlstr" | xml sel -T -t -m "/${xpath}" -v '..')"
    xmlstr="$(printf '%s' "$xmlstr" | xmlstarlet ed -u "/${xpath}/.." -v "" --subnode "." --type elem -n "$name" -v "$value" --subnode "." --type elem -n subvalue -v "$subvalue" )"
  else
    xmlstr="$(printf '%s' "$xmlstr" | xmlstarlet ed --subnode "/${xpath}/.." --type elem -n "$name" -v "$value")"
  fi
  printf '%s\n' "xpath: $xpath" "name: $name" "value: $value" "subvalue: $subvalue"; echo
done < <(echo "$xmlstr" | xmlstarlet el -a | LC_ALL=C sort -ru | grep -E '/@[^@]+$')  # only get absolute paths that have attributes

# delete all attributes, move subvalues to the last position and format XML output
xmlstr="$(printf '%s\n' "$xmlstr" | xmlstarlet ed -d "//*/@*" -m "//subvalue" "." | tidy -q -xml | xmlstarlet fo -R -o -s 3 -)"

printf '%s\n\n' "$xmlstr"

printf '%s\n' "$xmlstr" | xmlstarlet sel -T -t -m "//book/*[1]" -v "name(.)" -o ': ' -v . -n
printf '%s\n' "$xmlstr" | xmlstarlet sel -T -t -m "//book/*[2]" -v "name(.)" -o ': ' -v . -n
printf '%s\n' "$xmlstr" | xmlstarlet sel -T -t -m "//book/*[3]" -v "name(.)" -o ': ' -v . -n

)

Основной вывод должен быть:

<book>
   <year>2000</year>
   <author>Name</author>
   <subvalue>Book title</subvalue>
</book> 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...