Может ли HtmlAgilityPack обрабатывать xml-файл, который поставляется вместе с xsl-файлом, для рендеринга html? - PullRequest
5 голосов
/ 22 марта 2011

Мне было интересно, как HtmlAgilityPack мог бы прочитать XML-файл, содержащий XSL-файл, для рендеринга HTML. Существуют ли какие-либо параметры в классе HtmlDocument, которые могут помочь в этом, или мне нужно найти способ выполнить преобразование перед загрузкой его с помощью HtmlAgiliyPack? Если да для последнего, кто-нибудь знает хорошую библиотеку или метод для такого преобразования? Ниже приведен пример веб-сайта, который возвращает xml с файлом xls и кодом, который я хотел бы использовать.

var uri = new Uri("http://www.skechers.com/");
var request = (HttpWebRequest)WebRequest.Create(url);
var cookieContainer = new CookieContainer();

request.CookieContainer = cookieContainer;
request.UserAgent = @"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5";
request.Method = "GET";
request.AllowAutoRedirect = true;
request.Timeout = 15000;

var response = (HttpWebResponse)request.GetResponse();
var page = new HtmlDocument();
page.OptionReadEncoding = false;
var stream = response.GetResponseStream();
page.Load(stream); 

Этот код не выдает никаких ошибок, но анализируется XML, а не преобразование, а именно то, что я хочу.

Ответы [ 3 ]

3 голосов
/ 22 марта 2011

Html Agility Pack может помочь вам в двух моментах:

1) с ним проще получить инструкцию обработки Xml, поскольку она анализирует данные PI как Html, поэтому преобразует их в атрибуты

2) HtmlDocument реализует IXPathNavigable, поэтому его можно преобразовать напрямую с помощью механизма преобразования .NET Xslt.

Вот фрагмент кода, который работает.Мне пришлось добавить определенный XmlResover, чтобы правильно обрабатывать Xslt-преобразование, но я думаю, что это специфично для этого случая скешеров.

public static void DownloadAndProcessXml(string url, string userAgent, string outputFilePath)
{
    using (XmlTextWriter writer = new XmlTextWriter(outputFilePath, Encoding.UTF8))
    {
        DownloadAndProcessXml(url, userAgent, writer);
    }
}

public static void DownloadAndProcessXml(string url, string userAgent, XmlWriter output)
{
    UserAgentXmlUrlResolver resolver = new UserAgentXmlUrlResolver(url, userAgent);

    // WebClient is an easy to use class.
    using (WebClient client = new WebClient())
    {
        // download Xml doc. set User-Agent header or the site won't answer us...
        client.Headers[HttpRequestHeader.UserAgent] = resolver.UserAgent;
        HtmlDocument xmlDoc = new HtmlDocument();
        xmlDoc.Load(client.OpenRead(url));

        // determine xslt (note the xpath trick as Html Agility Pack does not support xml processing instructions)
        string xsltUrl = xmlDoc.DocumentNode.SelectSingleNode("//*[name()='?xml-stylesheet']").GetAttributeValue("href", null);

        // download Xslt doc
        client.Headers[HttpRequestHeader.UserAgent] = resolver.UserAgent;
        XslCompiledTransform xslt = new XslCompiledTransform();
        xslt.Load(new XmlTextReader(client.OpenRead(url + xsltUrl)), new XsltSettings(true, false), null);

        // transform Html/Xml doc into new Xml doc, easy as HtmlDocument implements IXPathNavigable
        // note the use of a custom resolver to overcome this Xslt resolve requests
        xslt.Transform(xmlDoc, null, output, resolver);
    }
}

// This class is needed during transformation otherwise there are errors.
// This is probably due to this very specific Xslt file that needs to go back to the root document itself.
public class UserAgentXmlUrlResolver : XmlUrlResolver
{
    public UserAgentXmlUrlResolver(string rootUrl, string userAgent)
    {
        RootUrl = rootUrl;
        UserAgent = userAgent;
    }

    public string RootUrl { get; set; }
    public string UserAgent { get; set; }

    public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
    {
        WebClient client = new WebClient();
        if (!string.IsNullOrEmpty(UserAgent))
        {
            client.Headers[HttpRequestHeader.UserAgent] = UserAgent;
        }
        return client.OpenRead(absoluteUri);
    }

    public override Uri ResolveUri(Uri baseUri, string relativeUri)
    {
        if ((relativeUri == "/") && (!string.IsNullOrEmpty(RootUrl)))
            return new Uri(RootUrl);

        return base.ResolveUri(baseUri, relativeUri);
    }
}

И вы называете это так:

    string url = "http://www.skechers.com/";
    string ua = @"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5";
    DownloadAndProcessXml(url, ua, "skechers.html");
2 голосов
/ 22 марта 2011

Вы должны отобразить вывод XML и XSLT.Для этого вам нужно скачать XML, и вы уже сделали это.Затем проанализируйте XML, чтобы определить ссылку XSL.Затем вам нужно скачать XSL и применить его к документу XML.

Эти ссылки могут быть полезны

0 голосов
/ 22 марта 2011

Вот дополнительный код, который я использовал после получения ответа.Обратите внимание, что это хорошо только в том случае, если ответ «application / xml» и вам придется проверять наличие нулевых экземпляров объектов во всем.Кроме того, FormAssetSrc является частной функцией, которая принимает значение href и определяет, является ли он относительным протоколом, корнем или документом, и создает полностью квалифицированный URI.

var xmlStream = response.GetResponseStream();
var xmlDocument = new XPathDocument(xmlStream);
var styleNode = xmlDocument.CreateNavigator().SelectSingleNode("processing-instruction('xml-stylesheet')");
var hrefValue = Regex.Match((styleNode).Value, "href=(\"|')(?<url>.*?)(\"|')");
if(hrefValue.Success)
{
    var xslHref = FormAssetSrc(hrefValue.Groups["url"].Value, response.ResponseUri);
    var xslUri = new Uri(xslHref);
    var xslRequest = CreateWebRequest(xslUri);
    var xslResponse = (HttpWebResponse)xslRequest.GetResponse();
    var xslStream = new XPathDocument(xslResponse.GetResponseStream());
    var xslTransorm = new XslTransform();
    var sw = new System.IO.StringWriter();
    xslTransorm.Load(xslStream);
    xslTransorm.Transform(xmlDocument.CreateNavigator(), null, sw);
    page.Html.LoadHtml(sw.ToString());
}
...