C# - 是否有可能(以及如何)使用SgmlReader执行XSL转换

时间:2010-11-30 15:10:08

标签: c# html xml xslt sgmlreader

我需要使用 XSLT 转换 HTML 网页的内容 。因此我使用了SgmlReader并编写了下面显示的片段(我 我想,最后,它也是 XmlReader ......)

XmlReader xslr = XmlReader.Create(new StringReader(
    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
    "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">" +
    "<xsl:output method=\"xml\" encoding=\"UTF-8\" version=\"1.0\" />" +
    "<xsl:template match=\"/\">" +
    "<XXX xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><xsl:value-of select=\"count(//br)\" /></XXX>" +
    "</xsl:template>" +
    "</xsl:stylesheet>"));

XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xslr);

using (SgmlReader html = new SgmlReader())
{
    StringBuilder sb = new StringBuilder();
    using (TextWriter sw = new StringWriter(sb))
    using (XmlWriter xw = new XmlTextWriter(sw))
    {
        html.InputStream = new StringReader(Resources.html_orig);
        html.DocType = "HTML";

        try
        {
            xslt.Transform(html, xw);
            string output = sb.ToString();
            System.Console.WriteLine(output);
        }
        catch (Exception exc)
        {
            System.Console.WriteLine("{0} : {1}", exc.GetType().Name, exc.Message);
            System.Console.WriteLine(exc.StackTrace);
        }
    }
}

尽管如此,我收到了错误信息

NullReferenceException : Object reference not set to an instance of an object.
   at MS.Internal.Xml.Cache.XPathDocumentBuilder.Initialize(XPathDocument doc, IXmlLineInfo lineInfo, String baseUri, LoadFlags flags)
   at MS.Internal.Xml.Cache.XPathDocumentBuilder..ctor(XPathDocument doc, IXmlLineInfo lineInfo, String baseUri, LoadFlags flags)
   at System.Xml.XPath.XPathDocument.LoadFromReader(XmlReader reader, XmlSpace space)
   at System.Xml.XPath.XPathDocument..ctor(XmlReader reader, XmlSpace space)
   at System.Xml.Xsl.Runtime.XmlQueryContext.ConstructDocument(Object dataSource, String uriRelative, Uri uriResolved)
   at System.Xml.Xsl.Runtime.XmlQueryContext..ctor(XmlQueryRuntime runtime, Object defaultDataSource, XmlResolver dataSources, XsltArgumentList argList, WhitespaceRuleLookup wsRules)
   at System.Xml.Xsl.Runtime.XmlQueryRuntime..ctor(XmlQueryStaticData data, Object defaultDataSource, XmlResolver dataSources, XsltArgumentList argList, XmlSequenceWriter seqWrt)
   at System.Xml.Xsl.XmlILCommand.Execute(Object defaultDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlSequenceWriter results)
   at System.Xml.Xsl.XmlILCommand.Execute(Object defaultDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter writer, Boolean closeWriter)
   at System.Xml.Xsl.XmlILCommand.Execute(XmlReader contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter results)
   at System.Xml.Xsl.XslCompiledTransform.Transform(XmlReader input, XmlWriter results)

我找到了一种解决方法,将 HTML 转换为 XML ,然后应用转换,但这是一个效率低下的解决方案,因为:

  1. 中级 XHTML 输出进入缓冲区,因此需要额外的内存
  2. 转换过程需要额外的 CPU 处理 并且遍历相同的层次结构两次(理论上是不必要的)。
  3. 所以(因为我知道 StackOverflow 社区总能提供很好的答案,而其他 C#论坛让我感到非常失望; o)我会成为寻找反馈和建议,以便直接使用 HTML 执行 XSL 转换(即使 SgmlReader 需要被其他类似的库替换)。< / p>

    先谢谢

2 个答案:

答案 0 :(得分:3)

即使SgmlReader类正在扩展XmlReader类,也不意味着它的行为就像XmlReader一样。

从技术上讲,SgmlReaderXmlReader的子类也没有意义,因为SGML是XML的超集,而不是子集。

您没有写过转换的目的,但一般来说 HTML Agility Pack 是操作HTML的好选择。

答案 1 :(得分:1)

您是否尝试过使用HTML Agility Pack代替SgmlReader?您可以将html加载到其中,并直接对其进行转换。如果在内部创建XML文档,我不是肯定的 - 虽然看起来好像不是你可能想要将内存和CPU使用率与你尝试和丢弃的转换方法进行比较。

//You already have your xslt loaded into var xslt...

HtmlDocument doc = new HtmlDocument();
doc.Load( ... );  //load your HTML doc, or use LoadXML from a string, etc  
xslt.Transform(doc, xw);

另请参阅此问题:How to use HTML Agility pack