iTextSharp XMLWorker 未读取 <link> CSS 标签
iTextSharp XMLWorker Not Reading <link> CSS tags
所以我一直在为这个绞尽脑汁。这是以下代码:
string content = ConvertHTMLToXHTML(content); //This is something I wrote
var doc = new iTextSharp.text.Document(PageSize.LETTER, 10f, 10f, 10f, 0f);
var writer = PdfWriter.GetInstance(doc, ms);
doc.Open();
ICSSResolver cssResolver = null;
cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(false);
cssResolver.AddCss(@"code { padding: 2px 4px; }", "utf-8", true);
//****This is the key line******
cssResolver.AddCssFile(@"<the css file>", true);
var hpc = new HtmlPipelineContext(new CssAppliersImpl(new XMLWorkerFontProvider()));
hpc.SetAcceptUnknown(true).AutoBookmark(true).SetTagFactory(tagProcessors); // inject the tagProcessors
hpc.SetLinkProvider(new LinkProvider(currentWorkingDirectory));
var htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(doc, writer));
var pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
var worker = new XMLWorker(pipeline, true);
var xmlParser = new XMLParser(true, worker, Encoding.UTF8);
//Ok, now we can finally parse all this
using (var srHtml = new StringReader(content)) {
xmlParser.Parse(srHtml);
}
doc.Close();
注意我写 "This is the key line" 的那一行。这就是我用于调试目的的。
因此,在内容中,我在 <head>
标签中设置了有效的 <link href='[valid address]' rel="stylesheet" />
。预处理风格,我确保使用我的方法 ConvertHTMLtoXHTML 将内容解析为完全解析的 href(它使用 HTMLAgilityPack 并且我验证了内容具有完全解析的 URL)。完全解析的示例 url 就像 http://localhost/foo/bar.css
但是,内容不会使用 CSS 呈现。因此,我去了 AddCssFile(看到这是关键线)并尝试通过 URI 路径将文件添加到那里(这都在我的系统上,所以我使用“http://localhost/foo/bar/blah.css”)。这引发了一个异常,因为它找不到文件(异常是 System.IO.IOException: retrieve.file.from.nothing
)。
我然后通过AddCssFile(例如:D:\foo\bar\blah.css)去添加文件,因为它在我的文件系统上因此成功了!!
我的问题是,是否有办法让 XMLWorker 读取 link 标签(如果我已经完全解决了它们),而不是我必须找到所有 link 标签,翻译它们转到它们在我磁盘上的位置,然后通过 CSSResolver?
添加它们
附加信息:
- ASP.NetMVC 4
- iTextSharp 5.5.8
- iTextSharp.xmlworker 5.5.8
确定了一个解决方案 - 必须深入研究 iTextSharp 的源代码才能弄清楚发生了什么,因为我使用的是已编译的 DLL,并且异常消息并不是完全有用。
顺便说一句,这是2part-er
获取时需要验证CSS
我的网站只允许经过身份验证的用户使用该网站。因此,当 iTextSharp 在 FileRetrieveImpl
中发出 WebRequest
时,它发出了一个简单的未经身份验证的 GET 请求。然后请求失败并显示 401 - 未经授权,这又从 iTextSharp 抛出 retrieve.file.from.nothing
异常。
为了解决这个问题,我需要使用以下代码
WebRequest w = WebRequest.Create(url);
w.UseDefaultCredentials = true;
w.PreAuthenticate = true;
w.Credentials = CredentialCache.DefaultCredentials;
在提出请求之前。因此,我需要覆盖我正在使用的 ICSSResolver
解析器上的 FileRetrieve
。我决定我需要 FileRetrieveImpl
的当前实现,同时覆盖导致我悲伤的方法 ProcessFromHref
。
因此,我写了以下内容,我从 FileRetrieveImpl
.
复制并粘贴了我需要的项目
private class CustomFileRetriever : FileRetrieveImpl {
private static ILogger LOGGER = LoggerFactory.GetLogger(typeof(FileRetrieveImpl));
private IList<string> rootdirs;
private IList<string> urls;
public CustomFileRetriever() {
rootdirs = new List<string>();
urls = new List<string>();
}
private Uri DetectWithRootUrls(string href) {
foreach (string root in urls) {
try {
return new Uri(root + href);
} catch (UriFormatException) {
}
}
throw new UriFormatException();
}
public override void ProcessFromHref(string href, IReadingProcessor processor) {
if (LOGGER.IsLogging(Level.DEBUG)) {
LOGGER.Debug(string.Format(LocaleMessages.GetInstance().GetMessage("retrieve.file.from"), href));
}
Uri url = null;
bool isfile = false;
string f = href;
try {
url = new Uri(href);
} catch (UriFormatException) {
try {
url = DetectWithRootUrls(href);
} catch (UriFormatException) {
// its probably a file, try to detect it.
isfile = true;
if (!(File.Exists(href))) {
isfile = false;
foreach (string root in rootdirs) {
f = Path.Combine(root, href);
if (File.Exists(f)) {
isfile = true;
break;
}
}
}
}
}
Stream inp = null;
if (null != url) {
//***********************
//Begin changed part
//***********************
WebRequest w = WebRequest.Create(url);
w.UseDefaultCredentials = true;
w.PreAuthenticate = true;
w.Credentials = CredentialCache.DefaultCredentials;
//***********************
//End changed part
//***********************
try {
inp = w.GetResponse().GetResponseStream();
} catch (WebException) {
throw new IOException(LocaleMessages.GetInstance().GetMessage("retrieve.file.from.nothing"));
}
} else if (isfile) {
inp = new FileStream(f, FileMode.Open, FileAccess.Read, FileShare.Read);
} else {
throw new IOException(LocaleMessages.GetInstance().GetMessage("retrieve.file.from.nothing"));
}
Read(processor, inp);
}
private void Read(IReadingProcessor processor, Stream inp) {
try {
int inbit = -1;
while ((inbit = inp.ReadByte()) != -1) {
processor.Process(inbit);
}
} catch (IOException e) {
throw e;
} finally {
try {
if (null != inp) {
inp.Close();
}
} catch (IOException e) {
throw new RuntimeWorkerException(e);
}
}
}
}
然后,我简单地覆盖了默认的文件检索器
ICSSResolver cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(false);
cssResolver.FileRetrieve = new CustomFileRetriever();
这解决了我打电话给 AddCssFile
并得到 retrieve.file.from.nothing
的问题。但是,我不只是想调用 AddCssFile,我想让 iTextSharp 识别链接。因此,这将引导我进入下一部分。
Link HTML 源中的标签需要特定属性
在我的问题陈述中,我写了它没有启动的原因 <link href='[valid address]' rel="stylesheet" />
。这是因为它缺少属性标记 type="text/css"
。因此,我应该 <link href='[valid address]' rel="stylesheet" type="text/css"/>
我通过阅读源代码确定了这一点(参见 Link)。在处理 XHTML 个标签时,它会看到标签完全存在并完全解析。
所以我一直在为这个绞尽脑汁。这是以下代码:
string content = ConvertHTMLToXHTML(content); //This is something I wrote
var doc = new iTextSharp.text.Document(PageSize.LETTER, 10f, 10f, 10f, 0f);
var writer = PdfWriter.GetInstance(doc, ms);
doc.Open();
ICSSResolver cssResolver = null;
cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(false);
cssResolver.AddCss(@"code { padding: 2px 4px; }", "utf-8", true);
//****This is the key line******
cssResolver.AddCssFile(@"<the css file>", true);
var hpc = new HtmlPipelineContext(new CssAppliersImpl(new XMLWorkerFontProvider()));
hpc.SetAcceptUnknown(true).AutoBookmark(true).SetTagFactory(tagProcessors); // inject the tagProcessors
hpc.SetLinkProvider(new LinkProvider(currentWorkingDirectory));
var htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(doc, writer));
var pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
var worker = new XMLWorker(pipeline, true);
var xmlParser = new XMLParser(true, worker, Encoding.UTF8);
//Ok, now we can finally parse all this
using (var srHtml = new StringReader(content)) {
xmlParser.Parse(srHtml);
}
doc.Close();
注意我写 "This is the key line" 的那一行。这就是我用于调试目的的。
因此,在内容中,我在 <head>
标签中设置了有效的 <link href='[valid address]' rel="stylesheet" />
。预处理风格,我确保使用我的方法 ConvertHTMLtoXHTML 将内容解析为完全解析的 href(它使用 HTMLAgilityPack 并且我验证了内容具有完全解析的 URL)。完全解析的示例 url 就像 http://localhost/foo/bar.css
但是,内容不会使用 CSS 呈现。因此,我去了 AddCssFile(看到这是关键线)并尝试通过 URI 路径将文件添加到那里(这都在我的系统上,所以我使用“http://localhost/foo/bar/blah.css”)。这引发了一个异常,因为它找不到文件(异常是 System.IO.IOException: retrieve.file.from.nothing
)。
我然后通过AddCssFile(例如:D:\foo\bar\blah.css)去添加文件,因为它在我的文件系统上因此成功了!!
我的问题是,是否有办法让 XMLWorker 读取 link 标签(如果我已经完全解决了它们),而不是我必须找到所有 link 标签,翻译它们转到它们在我磁盘上的位置,然后通过 CSSResolver?
添加它们附加信息:
- ASP.NetMVC 4
- iTextSharp 5.5.8
- iTextSharp.xmlworker 5.5.8
确定了一个解决方案 - 必须深入研究 iTextSharp 的源代码才能弄清楚发生了什么,因为我使用的是已编译的 DLL,并且异常消息并不是完全有用。
顺便说一句,这是2part-er
获取时需要验证CSS
我的网站只允许经过身份验证的用户使用该网站。因此,当 iTextSharp 在 FileRetrieveImpl
中发出 WebRequest
时,它发出了一个简单的未经身份验证的 GET 请求。然后请求失败并显示 401 - 未经授权,这又从 iTextSharp 抛出 retrieve.file.from.nothing
异常。
为了解决这个问题,我需要使用以下代码
WebRequest w = WebRequest.Create(url);
w.UseDefaultCredentials = true;
w.PreAuthenticate = true;
w.Credentials = CredentialCache.DefaultCredentials;
在提出请求之前。因此,我需要覆盖我正在使用的 ICSSResolver
解析器上的 FileRetrieve
。我决定我需要 FileRetrieveImpl
的当前实现,同时覆盖导致我悲伤的方法 ProcessFromHref
。
因此,我写了以下内容,我从 FileRetrieveImpl
.
private class CustomFileRetriever : FileRetrieveImpl {
private static ILogger LOGGER = LoggerFactory.GetLogger(typeof(FileRetrieveImpl));
private IList<string> rootdirs;
private IList<string> urls;
public CustomFileRetriever() {
rootdirs = new List<string>();
urls = new List<string>();
}
private Uri DetectWithRootUrls(string href) {
foreach (string root in urls) {
try {
return new Uri(root + href);
} catch (UriFormatException) {
}
}
throw new UriFormatException();
}
public override void ProcessFromHref(string href, IReadingProcessor processor) {
if (LOGGER.IsLogging(Level.DEBUG)) {
LOGGER.Debug(string.Format(LocaleMessages.GetInstance().GetMessage("retrieve.file.from"), href));
}
Uri url = null;
bool isfile = false;
string f = href;
try {
url = new Uri(href);
} catch (UriFormatException) {
try {
url = DetectWithRootUrls(href);
} catch (UriFormatException) {
// its probably a file, try to detect it.
isfile = true;
if (!(File.Exists(href))) {
isfile = false;
foreach (string root in rootdirs) {
f = Path.Combine(root, href);
if (File.Exists(f)) {
isfile = true;
break;
}
}
}
}
}
Stream inp = null;
if (null != url) {
//***********************
//Begin changed part
//***********************
WebRequest w = WebRequest.Create(url);
w.UseDefaultCredentials = true;
w.PreAuthenticate = true;
w.Credentials = CredentialCache.DefaultCredentials;
//***********************
//End changed part
//***********************
try {
inp = w.GetResponse().GetResponseStream();
} catch (WebException) {
throw new IOException(LocaleMessages.GetInstance().GetMessage("retrieve.file.from.nothing"));
}
} else if (isfile) {
inp = new FileStream(f, FileMode.Open, FileAccess.Read, FileShare.Read);
} else {
throw new IOException(LocaleMessages.GetInstance().GetMessage("retrieve.file.from.nothing"));
}
Read(processor, inp);
}
private void Read(IReadingProcessor processor, Stream inp) {
try {
int inbit = -1;
while ((inbit = inp.ReadByte()) != -1) {
processor.Process(inbit);
}
} catch (IOException e) {
throw e;
} finally {
try {
if (null != inp) {
inp.Close();
}
} catch (IOException e) {
throw new RuntimeWorkerException(e);
}
}
}
}
然后,我简单地覆盖了默认的文件检索器
ICSSResolver cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(false);
cssResolver.FileRetrieve = new CustomFileRetriever();
这解决了我打电话给 AddCssFile
并得到 retrieve.file.from.nothing
的问题。但是,我不只是想调用 AddCssFile,我想让 iTextSharp 识别链接。因此,这将引导我进入下一部分。
Link HTML 源中的标签需要特定属性
在我的问题陈述中,我写了它没有启动的原因 <link href='[valid address]' rel="stylesheet" />
。这是因为它缺少属性标记 type="text/css"
。因此,我应该 <link href='[valid address]' rel="stylesheet" type="text/css"/>
我通过阅读源代码确定了这一点(参见 Link)。在处理 XHTML 个标签时,它会看到标签完全存在并完全解析。