.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> 与相对路径导致错误的主要内容,如果未能解决你的问题,请参考以下文章

Linux内核分析实验二

WEB开发经验点滴

X-005 FriendlyARM tiny4412 uboot移植之时钟初始化

X-004 FriendlyARM tiny4412 uboot移植之点亮指路灯

X-003 FriendlyARM tiny4412 uboot移植之添加相应目录文件

X-007 FriendlyARM tiny4412 u-boot移植之内存初始化