0

我是反应式扩展初学者。Gideon Engelberth 在我的问题中给了我关于 Reactive Extension 的出色回答。

如何使用 LINQ 或 Rx 在一个方法链上将 img url 转换为 HTML 中的 BASE64 字符串

现在我有第二个问题,即如何将 IObservable 返回值分配给 XDocument 实例。

Gideon 给了我下面的样品。

    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

所以你在这里所拥有的只有一半有用。似乎 Gideon 已经回答了您的问题,但也许不知道您的额外要求。所以我假设你想要一个 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(); 

但是,这也有问题。第一,我们正在变异状态。在处理并发时,这不是一个好的开始。我们真的应该返回一个具有正确值的新 XDoc。第二,这似乎更像是一个 TPL 问题而不是 Rx 问题。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 回答