More than 1 year has passed since last update.

Xamarin Advent CalendarC# Advent Calendar の17日目の記事です。

先日、Xamarin.AndroidなプロジェクトでHtmlAgilityPackをNugetからぶち込んでもうまく動かなかった(XPathが利用できなかった)ので解決策をメモしておきます。

XPath使いたい...

酢酸先生がPCLバージョンを使う記事を書かれているのですが、どうせならXPath(SelectNodes,SelectSingleNode)使いたいじゃんということで、本家のコードを一部修正して使います。
Xamarin.iOSでHtml Agility Packを使ってHTMLをスクレイピングする - 酢ろぐ!

それでは手順を

まず、HtmlAgilityPackのコードを Html Agility Pack - Source Code から落としてきます。 ※私がこの記事を書いている2014/12/16現在、バージョンは1.4.0です。

1. HtmlAgilityPack.csprojを修正

Release\1_4_0\HtmlAgilityPack\HtmlAgilityPack.csprojを以下のように修正します。

28行目
修正前

 <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>

修正後

 <TargetFrameworkVersion>v(使いたいXamarin.Androidのバージョン)</TargetFrameworkVersion>

128行目
修正前

 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

修正後

 <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />

2. HtmlWeb.csを修正

次に、VisualStudioなりXamarinStudioなりで修正したHtmlAgilityPack.csprojを開き、コンパイルシンボルにXAMARINを追加した後、HtmlWeb.csを以下のように修正します。

883-895行
修正前

HtmlWeb.cs
if (!SecurityManager.IsGranted(new DnsPermission(PermissionState.Unrestricted)))
{
    //do something.... not at full trust
    try
    {
        RegistryKey reg = Registry.ClassesRoot;
        reg = reg.OpenSubKey(extension, false);
        if (reg != null) contentType = (string)reg.GetValue("", def);
    }
    catch (Exception)
    {
        contentType = def;
    }
}

修正後

HtmlWeb.cs
#if !XAMARIN
    if (!SecurityManager.IsGranted(new DnsPermission(PermissionState.Unrestricted)))
    {
        //do something.... not at full trust
        try
        {
            RegistryKey reg = Registry.ClassesRoot;
            reg = reg.OpenSubKey(extension, false);
            if (reg != null) contentType = (string)reg.GetValue("", def);

            contentType = def;
        }
        catch (Exception)
        {
            contentType = def;
        }
    }
#endif

924-936行
修正前

HtmlWeb.cs
if (SecurityManager.IsGranted(new RegistryPermission(PermissionState.Unrestricted)))
{
    try
    {
        RegistryKey reg = Registry.ClassesRoot;
        reg = reg.OpenSubKey(@"MIME\Database\Content Type\" + contentType, false);
        if (reg != null) ext = (string)reg.GetValue("Extension", def);
    }
    catch (Exception)
    {
        ext = def;
    }
}

修正後

HtmlWeb.cs
if (SecurityManager.IsGranted(new RegistryPermission(PermissionState.Unrestricted)))
{
#if !XAMARIN
    try
    {
        RegistryKey reg = Registry.ClassesRoot;
        reg = reg.OpenSubKey(@"MIME\Database\Content Type\" + contentType, false);
        if (reg != null) ext = (string)reg.GetValue("Extension", def);
    }
    catch (Exception)
    {
        ext = def;
    }
#else
    ext = def;
#endif
}

3. ビルド

無事HtmlAgilityPack.dllが生成されていたらOKです。

最後に

とりあえず動くようにしただけなのでHtmlWebの挙動にどう影響するのか不明ですが、SelectNodes,SelectSingleNodeあたりはちゃんと動きます(実機での動作を確認)。

どなたか

new DnsPermission(PermissionState.Unrestricted)

のよさげな修正案をお持ちの方いらっしゃいましたら教えてください...(というかこの記事がベストなのか不明)

Xamarin Advent CalendarC# Advent Calendar 18日目の記事はそれぞれ yuwata さんと wilfrem さんです。よろしくお願いします。