0

私はリアクティブ拡張の初心者です。Gideon Engelberth は、私の質問で Reactive Extension について素晴らしい回答をくれました。

LINQ または Rx を使用して、1 つのメソッド チェーンで HTML の img url を BASE64 文字列に変換する方法

ここで、IObservable の戻り値を XDocument インスタンスに割り当てる方法という 2 番目の質問があります。

ギデオンは私に以下のサンプルをくれました。

    public IObservable<Unit> ReplaceImageLinks(XDocument document)
    {
        return (from element in GetImages(document)
                let address = new Uri(element.Attribute("src").Value)
                select (from data in DownloadAsync(address)
                        select Convert.ToBase64String(data)
                       ).Do(base64 => element.Attribute("src").Value = base64)
               ).Merge()
                .IgnoreElements()
                .Select(s => Unit.Default);
    }

私はこのようにしたいと思います。つぼみ 難しそうですね…

public void Convert(XDocument input, out XDocument output)
{
    output = ReplaceImageLinks(input);
}
4

1 に答える 1

0

したがって、ここにあるものは半分しか役に立ちません。ギデオンはあなたの質問に答えたようですが、おそらくあなたの追加の要件を知らなかったのでしょう。したがって、XDoc を取得し、すべての Image src 属性をパスから、パスが表す BASE64 コンテンツに変換する必要があると仮定します。すべての処理が完了したら、その新しい XDoc オブジェクトを返します。正しい?

その場合は、これを行うことができます。

public IObservable<XDocument> ReplaceImageLinks(XDocument document)
{
    return Observable.Create<XDocument>(o=>
    {
        try{
            var images = document.Descendants("Image");
            Parallel.ForEach(images, SwapUriForContent);
            o.OnNext(document);
            o.OnCompleted();
        }
        catch(Exception ex)
        {
            o.OnError(ex);
        }
        return Disposable.Empty;    //Should really be a handle to Parallel.ForEach cancellation token.
    });
}

private static void SwapUriForContent(XElement imageElement)
{
    var address = new Uri(imageElement.Attribute("src").Value, UriKind.RelativeOrAbsolute);
    imageElement.Attribute("src").Value = Download(address);
}

public static string Download(Uri input)
{
    //TODO Replace with real implemenation
    return input.ToString().ToUpper();
}

私がちょうどテストした

string str =
    @"<?xml version=""1.0""?>
    <!-- comment at the root level -->
    <Root>
        <Child>Content</Child>
        <Image src=""image.jpg""/>
        <Child>
            <Image src=""image2.jpg""/>
        </Child>
    </Root>";
XDocument doc = XDocument.Parse(str);
ReplaceImageLinks2(doc).Dump(); 

ただし、これには問題があります。1つ目は、状態を変異させていることです。これは、同時実行性を扱う場合に最適な出発点ではありません。正しい値を持つ新しい XDoc を返す必要があります。2番目に、これはRxの問題よりもTPLの問題のようです。Rx は、受信データのストリーミングを処理するのに最適です。ここで必要なのは、並列処理を実行することです。はるかに良い選択肢は、単にタスクを実行することだと思います。

public Task<XDocument> ReplaceImageLinks3(XDocument source)
{
    return Task.Factory.StartNew(()=>
    {
        var copy = new XDocument(source);
        var images = copy.Descendants("Image");
        Parallel.ForEach(images, SwapUriForContent);
        return copy;
    });
}

IntroToRx.comの私の本の「いつ Rx を使用するか」のセクションを参照してください。

于 2012-07-03T23:05:31.940 に答える