Bashを使用してXMLデータを変数に分割する

Bashを使用してXMLデータを変数に分割する

サービスからいくつかのファイルをダウンロードしようとしています。これらのファイルはXMLファイルにあります。 XMLファイルには、ダウンロードするファイルが1つ以上ある場合があります。しかし、今スクリプトに問題があります。各ファイルを個別にダウンロードできるように、XMLLINTの文字列を配列に分割する方法がわかりません。

文字列を複数の変数に分割し、各ファイルのURL文字列をダウンロードする必要があります。

ところで、201701_1ファイルは重複せず、カールを使ってダウンロードするのに問題はありません。ちなみに、Coverage.zipファイルが重複してカールで覆われています。私はします: その後、カールを使用して単一のファイルをダウンロードします。

curl -O -b cookie $URL 

現在私のスクリプトは次のとおりです。

while read edition; do   XML="<?xml version=\"1.0\"
encoding=\"UTF-8\"?> <download-area>   <files>
    <file>
      <url>https://google.com/411/201701_01_01.zip</url>
    </file>
    <file>
      <url>https://google.com/411/201701_01_02.zip</url>
    </file>   </files> </download-area>
    "
    URL=$(echo $XML | xmllint --xpath \
    "/*[name()='download-area']/*[name()='files']/*[name()='file']/*[name()='url']/text()" -)

    echo "URL:: " $URL

done < $LATEST_EDITION

LATEST_EDITION は行を含むファイルです。

私の質問は:VAR_1とVAR_2を複数のURLに分割して個別にダウンロードするにはどうすればよいですか? Coverage.zipを上書きするのを防ぐ方法は?

答え1

xmllintXML文書から情報を抽出することは役に立ちません。xmlstarletor xml_grep(XML :: Twigからperl)またはを考慮することができますxml2

以下を使用して、xmllint一度に1つの文字列を抽出できます。

VAR1=$(printf '%s\n' "$XML" |
  xmllint --xpath '/download-area/files/file[1]/url/text()' -)
VAR2=$(printf '%s\n' "$XML" |
  xmllint --xpath '/download-area/files/file[2]/url/text()' -)

ここのように改行文字を含まない値の場合、bash's はreadarray次のように使用できます.

readarray -t var < <(
  xmlstarlet sel -t -v /download-area/files/file/url  <<< "$XML")

または

readarray -t var < <(
  xml2 <<< "$XML" | sed -n 's|^/download-area/files/file/url=||p')

または:

readarray -t var < <(
  xml_grep --text_only /download-area/files/file/url <<< "$URL")

答え2

次のようにしてみてください。

declate -a url_array
url_array=(`echo $XML | grep -o "http.*zip" | tr '\n' ' '`)

答え3

xmllintXMLを分割するのに良いツールではありません。 2つの問題(XML解析と固有URLの保証)を強力な方法で解決するには、次のようにbashしますxmlstarlet

#!/bin/bash
XML='<?xml version="1.0" encoding="UTF-8"?>
<download-area>
  <files>
    <file>
      <url>https://google.com/411/201701_01_01.zip</url>
    </file>
    <file>
      <url>https://google.com/411/201701_01_02.zip</url>
    </file>
  </files>
</download-area>'

# IFS=$'\n'   ## required if URLs contains spaces
urls=( $(xml select -t -m  "/download-area/files/file" -v url -nl  <<< $XML ) )

declare -A unique  # associative array
for uu in ${urls[*]}; do let unique[$uu]++; done

for uu in "${!unique[@]}"; do
  printf "URL is %s\n" ${uu}
done

これは、テンプレート()がxpath()と一致し、ノードの値がテンプレート()から選択され、各値()の後に改行文字が追加されるパターンxmlstarletに使用されます。 (xmlstarletはこれよりも柔軟性があるため、何度でも使用でき、必要な場所に任意のテキストを追加できます。)select-t-m-vurl-nl-v-o

また、リダイレクトを使用して/パイプを<<<保存しますecho

URLは通常のインデックス配列として保存されますurls。次に、配列を繰り返してURLをキーとして保存します。連想配列- これは一意性の問題を解決します(そして発生回数は各項目の値のままです)。

Bashの連想配列に慣れていない場合、2番目のループには追加の説明が必要です。この表現は"${unique[@]}"すべてを拡張します。価値配列を使用して"${!unique[@]}"すべての項目を展開します。索引配列の場合、次のように配列データをダンプすると意味がありますdeclare -p unique

declare -A unique=([https://google.com/411/201701_01_01.zip]="1" 
                   [https://google.com/411/201701_01_02.zip]="1" )

ループ内でこれを行うこともできますが、理解するのは少し難しいかもしれません。

while read line; do
  [[ -n "$line" ]] && let unique[$line]++ 
done < <(xml sel -t -m  "/download-area/files/file" -v url  -nl <<< $XML)

xmlXMLstarletは次のようにインストールできます。xmlstarlet

答え4

sedを使用して出力を解析することを検討してくださいxmllint。短縮されたXPath式を参照してください!

URL=$( echo $XML | xmllint --xpath "//url" - | sed -e 's/<url>//g' -e 's/<\/url>/\n/g' )

printf "%s\n" "$URL"

1行に1つのURLが出力されます。

関連情報