Azure の Public の Blob のリストを取得したいんだけど、Azure CLI や、Azure SDKなし、つまり認証なしでやりたいと思っていました。実際に調べてみると、出来るようです。
ところが、人生は甘くないようで、戻り値が、XMLのようです。おお、、、めんどくさい香りしかしない、、、ところが、C#は意外にXMLに強いようで意外と簡単に行けました。その説明をしてみたいと思います。
解析したい XML ファイル
上記のAPIの戻り値は次のようなXMLです。やりたいことは、ここのUrlに記述されている値を取得したいなと思います。
<EnumerationResults ContainerName="https://some.blob.core.windows.net/healthcheck">
<Blobs>
<Blob>
<Name>azure-functions-core-tools.json</Name>
<Url>https://some.blob.core.windows.net/healthcheck/azure-functions-core-tools.json</Url>
<Properties>
<Last-Modified>Sun, 07 Jun 2020 01:53:41 GMT</Last-Modified>
<Etag>0x8D80A859AB1ED42</Etag>
<Content-Length>88</Content-Length>
<Content-Type>application/json</Content-Type>
<Content-Encoding/>
<Content-Language/>
<Content-MD5>a+BCgjwVn3JqvjG3MezREQ==</Content-MD5>
<Cache-Control/>
<BlobType>BlockBlob</BlobType>
<LeaseStatus>unlocked</LeaseStatus>
</Properties>
</Blob>
<Blob>
<Name>azure-functions-host.json</Name>
<Url>https://some.blob.core.windows.net/healthcheck/azure-functions-host.json</Url>
<Properties>
<Last-Modified>Sun, 07 Jun 2020 01:53:41 GMT</Last-Modified>
<Etag>0x8D80A859AB3E96C</Etag>
<Content-Length>88</Content-Length>
<Content-Type>application/json</Content-Type>
<Content-Encoding/>
<Content-Language/>
<Content-MD5>EktDgZOalVaExkgWs8JqgQ==</Content-MD5>
<Cache-Control/>
<BlobType>BlockBlob</BlobType>
<LeaseStatus>unlocked</LeaseStatus>
</Properties>
</Blob>
</Blobs>
<NextMarker/>
</EnumerationResults>
実装
XMLの読み込み
最初のAPIの説明の通りにリクエストを実施します。HttpClient すらも不要です。これは簡単ですね。
var list = XDocument.Load("https://some.blob.core.windows.net/healthcheck?restype=container&comp=list")
要素の取得
今回は、Blob の下にある Url を取得したいです。階層会ってめんどくさそうやなと思いきや、Linqが使えるようです。
var names = list.Descendants("Blob").Select(p => p.Element("Url")?.Value);
LINQ to XML に記述があるのですが、listはXmlDocumentのオブジェクトなのですが、このクラスにはdecendentsメソッドはありません。これは、System.Xml.Linq.XNameパッケージの拡張メソッドです。このXMLドキュメントのdecendentsつまりルートから考えた時の子孫を検索して、IEnumerable<XElement>として返却してくれます。IEnumerableが帰るので、Linqし放題です。更新系のメソッドなども存在するので、ご興味がある人はXContainer Classをご覧ください。
子要素の取得
私は Element("Url")?.Valueで、Blobの子ElementであるUrlを参照しています。
アトリビュートの取得
アトリビュート、つまり、XMLのアトリビュート、下記の例では AddressのType=Shippingを取得したい場合は、p.Attribute("Type") で取得することができます。
<Address Type="Shipping">
<Name>Ellen Adams</Name>
<Street>123 Maple Street</Street>
<City>Mill Valley</City>
<State>CA</State>
<Zip>10999</Zip>
<Country>USA</Country>
</Address>
おわりに
今回は読込だけを知りたかったのでこの程度の調査で終了しますが、忘れないように記述しておきました。思ったよりずっと簡単でよかったです。