.net/xslt: <xsl:include> 与相对路径导致错误
Posted
技术标签:
【中文标题】.net/xslt: <xsl:include> 与相对路径导致错误【英文标题】:.net/xslt: <xsl:include> with relative path causes error 【发布时间】:2017-12-07 16:28:33 【问题描述】:我的 C# 程序必须生成不同版本的不同 PDF 文档。基本页眉和页脚是相同的。所以我想把它们放在一个单独的 xsl 中。
这里是我喜欢的文件夹结构:
/common/headerFooter.xsl
/docVersion1/doc1.xsl
/docVersion1/doc2.xsl
...
/docVersion2/doc1a.xsl
/docVersion2/doc2a.xsl
...
所以实际上包含在例如doc1.xsl 应该像这样工作:
<xsl:include href="../common/headerFooter.xsl"/>
但我收到以下错误:
[Fatal Error] :1:1 Content is not allowed in prolog.
System-ID unknown; Zeilennummer1; Spaltennummer1; org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.
好的 - 第一个想法是关于 BOM 等,但不是。文件完全没问题 (!)。
所以我做了这个尝试:
/docVersion1/headerFooter.xsl
/docVersion1/doc1.xsl
/docVersion1/doc2.xsl
...
/docVersion2/headerFooter.xsl
/docVersion2/doc1a.xsl
/docVersion2/doc2a.xsl
...
在 doc1.xsl(等)中:
<xsl:include href="headerFooter.xsl"/>
这个功能...(!?!?)
问题出在哪里?
第一次尝试的相对路径是正确的。 Visual Studio 也告诉它。而且我认为将 headerFooter.xsl 的副本放在每个 docVersion 文件夹中会很奇怪。
最近的代码:
// xmlToPdfInfo holds all important information about the stylesheets.
// xmlToPdfInfo.XslPath : path to the doc_.xsl-files
java.io.File xsltfile = new java.io.File(xmlToPdfInfo.XslPath);
StreamSource streamSource = new StreamSource(xsltfile.getAbsoluteFile());
// ERROR LINE:
Transformer transformer = factory.newTransformer(streamSource);
// It seems there is already an analyse for all includes and it fails to
// get the relativ path correctly.
// No chance to put additional information e.g. about the path using
// parameters.
// Set the value of a <param> in the stylesheet);
if (xmlToPdfInfo.Arguments != null)
IList keys = xmlToPdfInfo.Arguments.GetKeyList();
foreach (var key in keys)
Object value = xmlToPdfInfo.Arguments[key];
try
transformer.setParameter(key.ToString(), value);
catch (Exception spe)
Console.WriteLine(spe.Message);
提醒:将 headerFooter.xsl 放在 docVersion 文件夹中所有工作。后退似乎有问题(../)。
【问题讨论】:
所以你说它是 .NET 和 C# 但例外是关于org.xml.sax.SAXParseException
通常是 Java。您能否向我们展示最小但完整的 XSLT、XML、C# 示例,以便我们重现该问题?例如,当您尝试将 URL 传递给期望 XML 作为字符串的方法时,就会发生该错误。
我用 IKVM 7.2.4630.5 转移了 fop 2.1 jar。相当标准。创建新 Transformer 时会出现错误。
但是你说的是一个 C# 程序。我没有看到 C#...
@Michael:C# 和 Java 在语法上非常接近...... "foreach (var key in keys)" not for (var key : keys) 和 "Console.WriteLine" not System.out.println
是的,抱歉,被所有的 Java 名称弄糊涂了。恐怕我看不出有什么问题。可能值得添加一个 URIResolver 并监视它是如何被调用的。或者切换到撒克逊人;-)
【参考方案1】:
终于我自己得到了答案:
重点是写自己的URIResolver!这是我的版本/方式:
public void createPDF(...)
...
xmlToPdfInfo.Resolver = new XmlResourceResolver(...);
xmlToPdfInfo.XslPath = getPathToMyStyleSheet();
xmlToPdfInfo.IncludedDocsList = GetIncludedDocsList();
Utils.XmlToPdf(xmlToPdfInfo, outputStream);
protected SortedList GetIncludedDocsList()
SortedList sortedList = new SortedList();
sortedList.Add("headerFooter.xsl", BasePath() + ".common.headerFooter.xsl");
...
return sortedList;
public class Utils
private static XmlResourceResolver resolver;
private static SortedList includedDocsList;
/// <summary>Gets a PDF as stream from an xml-file, rendered by an xsl stylesheet</summary>
/// <param name="xmlToPdfInfo">Contains all input information</param>
/// <param name="outputStream">resulting PDF as a stream</param>
public static void XmlToPdf(XmlToPdfInfo xmlToPdfInfo, OutputStream outputStream)
resolver = xmlToPdfInfo.Resolver;
includedDocsList = xmlToPdfInfo.IncludedDocsList;
...
public class VgUriResolver : URIResolver
/// <summary>Gets the embedded file for the UriResolver</summary>
/// <param name="href">relative path to the file (the path that has been put in <xsl:include>)</param>
/// <param name="baseUri">base path</param>
/// <returns>The embedded source </returns>
public Source resolve(String href, String baseUri)
if (includedDocsList != null)
IList keys = includedDocsList.GetKeyList();
String hrefFilename = Path.GetFileName(href);
foreach (var key in keys)
String pfad = (string) includedDocsList[key];
String filename = (String) key;
try
// "hard-match": if by chance we can get the file
// by the real resource path.
if (pfad.Equals(href))
byte[] bArr = ReadToEnd(resolver.GetManifestResourceStream(pfad));
return new StreamSource(new ByteArrayInputStream(bArr));
// "soft-match": looks for the filenames without any path.
// Attention: works only fine if you **don't** have to include files
// with same name (different path)
if (filename.Equals(hrefFilename))
byte[] bArr = ReadToEnd(resolver.GetManifestResourceStream(pfad));
return new StreamSource(new ByteArrayInputStream(bArr));
catch (Exception)
try
return readFromFileStream(href);
catch (Exception)
return readFromFileStream(hrefFilename);
return new StreamSource(new StringReader(href));
事实上,你写的更多的是一个键/占位符,用自己的 URIResolver 找到真正的文件。
嗯……
【讨论】:
以上是关于.net/xslt: <xsl:include> 与相对路径导致错误的主要内容,如果未能解决你的问题,请参考以下文章
X-005 FriendlyARM tiny4412 uboot移植之时钟初始化
X-004 FriendlyARM tiny4412 uboot移植之点亮指路灯