タイトルだけ見てもさっぱり何のことかわからないかもですが、S3のオブジェクト一覧をとるAPIであるListObjectV2での出すこのエラーでえらいハマったので誰かのお役に立てばと思い投稿しました。
以下、コードはrubyです。
基本的な使い方
まず、sampleバケットに下記のようなオブジェクトがあるとします。
sample/
├ aaa/
├ aaa1/
└ aaa2.txt
└ aaa3.txt
├ bbb
├ bbb1
└ bbb2
└ ccc.txt
この時、バケットだけを指定するとsampleバケットのすべてのオブジェクト一覧が取得できます。
# s3はAws::S3::Clientのオブジェクト
res = s3.list_objects_v2({bucket: 'sample'})
res.contents.each do |k|
p k.key
end
出力
aaa/
aaa/aaa1
aaa/aaa2.txt
aaa/aaa3.txt
bbb/
bbb/bbb1/
bbb/bbb2/
ccc.txt
では、aaaフォルダのオブジェクト一覧を取得するためにprefixを指定してみましょう。
res = s3.list_objects_v2({bucket: 'sample', prefix: 'aaa'})
res.contents.each do |k|
p k.key
end
出力
aaa/
aaa/aaa1
aaa/aaa2.txt
aaa/aaa3.txt
S3ではフォルダという概念はないのですが、aaaフォルダ以下のオブジェクト一覧が取得できました。
逆に、拡張子がtxtのオブジェクト一覧を取得するためにdelimiterを指定してみましょう。
公式の文書の例だと「/」とかで、区切り文字じゃないとダメなのかと一瞬思いますが、「.txt」のように文字列を指定しても大丈夫です。
res = s3.list_objects_v2({bucket: 'sample', delimiter: '.txt'})
res.contents.each do |k|
p k.key
end
出力
aaa/aaa2.txt
aaa/aaa3.txt
ccc.txt
このように拡張子を指定してオブジェクトの一覧を取得できます。
もちろん両方をあわせて「aaaフォルダのtxtファイル」という指定もできます。
res = s3.list_objects_v2({bucket: 'sample', prefix: 'aaa', delimiter: '.txt'})
res.contents.each do |k|
p k.key
end
出力
aaa/aaa2.txt
aaa/aaa3.txt
唐突にエラーが...
以上、なんの問題もなく基本的な操作はできたのですが、なぜかとある検索をした時に「xmlParseCharRef: invalid xmlChar value 8」というエラーが出ました。
今回、不思議だったのはここでエラーだけ見ると何かXMLのパースに失敗している様子。
ただ、どんなにググっても有力な情報が見つからないので自力でエラーになっているオブジェクトを特定したところ、機種依存文字が含まれたキーを持つオブジェクトがありました...
しかも、S3の画面上では表示されず特定にものすごい時間がかかりました。
というわけで、どなたが同じエラーで困った時に参考になれば幸いです。
参考にしたサイト
・ListObjectV2のAPIドキュメント
https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html#API_ListObjectsV2_RequestSyntax
・機種依存文字チェッカー
https://form.submitmail.jp/tools/check/