代码之家  ›  专栏  ›  技术社区  ›  Cerebrus

如何解析从字符串加载xsl的转换中包含的xsl?

  •  5
  • Cerebrus  · 技术社区  · 15 年前

    .NET 2.0/VS2005版

    我想用 XslCompiledTransform 类来执行xsl转换。我有两个xsl文件,第一个文件包含对另一个文件的引用,其格式为 <xsl:include> 声明:

    Main.xsl:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:include href="Included.xsl" />
      ...
      ...
    </xsl:stylesheet>
    

    现在,如果我可以将“main.xsl”文件本身加载为一个uri,那么我的转换代码将简单到:

    // This is a function that works. For demo only.
    private string Transform(string xslFileURI)
    {
      XslCompiledTransform xslt = new XslCompiledTransform();
    
      // This load works just fine, if I provide the path to "Main.xsl".
      // The xsl:include is automatically resolved.
      xslTransform.Load(xslFileURI);
    
      StringWriter sw = new StringWriter();
      xslt.Transform(Server.MapPath("~/XML/input.xml"), null, sw);
      return sw.ToString();
    }
    

    问题是,我将main.xsl文件的内容作为字符串接收,并需要将该字符串作为 XmlReader/IXpathNavigable . 这是目前必要的限制。 当我试图使用 XmlReader/XpathDocument ,它失败,因为代码在 C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ 文件夹!很明显, XmlResolver 无法解析相对url,因为它只接收字符串作为输入xsl。

    我在这方面的努力看起来像:

    // This doesn't work! Halp!
    private string Transform(string xslContents)
    {
      XslCompiledTransform xslt = new XslCompiledTransform();
      XmlUrlResolver resolver = new XmlUrlResolver();
      resolver.Credentials = CredentialCache.DefaultCredentials;
    
      //METHOD 1: This method does not work.
      XmlReaderSettings settings = new XmlReaderSettings();
      settings.XmlResolver = resolver;
      XmlReader xR = XmlReader.Create(new StringReader(xslContents), settings);
      xslt.Load(xR);    // fails
    
      // METHOD 2: Does not work either.
      XPathDocument xpDoc = new XPathDocument(new StringReader(xslContents));
      xslt.Load(xpDoc, new XsltSettings(true, true), resolver);  //fails.
    
      StringWriter sw = new StringWriter();
      xslt.Transform(Server.MapPath("~/XML/input.xml"), null, sw);
      return sw.ToString();
    }
    

    我试过用 ResolveUri XmlUrlResolver的方法来获取 Stream 引用要包含的xsl文件,但对如何使用此流感到困惑。听着,我该怎么告诉 XslCompiledTransform 对象以在main.xsl xmlreader之外使用此流:

    Uri mainURI = new Uri(Request.PhysicalApplicationPath + "Main.xsl");
    Uri uri = resolver.ResolveUri(mainURI, "Included.xsl");
    
    // I can verify that the Included.xsl file loads in the Stream below.
    Stream s = resolver.GetEntity(uri, null, typeof(Stream)) as Stream;
    
    // How do I use this Stream in the function above??
    


    任何帮助都非常感谢。对不起,我发了那么长的信!

    为了供您参考,异常堆栈跟踪如下所示:

    [FileNotFoundException: Could not find file 'C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\Included.xsl'.]
       System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) +328
       System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) +1038
       System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize) +113
       System.Xml.XmlDownloadManager.GetStream(Uri uri, ICredentials credentials) +78
       System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn) +51
       System.Xml.Xsl.Xslt.XsltLoader.CreateReader(Uri uri, XmlResolver xmlResolver) +22
       System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(Uri uri, Boolean include) +33
       System.Xml.Xsl.Xslt.XsltLoader.LoadInclude() +349
       System.Xml.Xsl.Xslt.XsltLoader.LoadRealStylesheet() +704
       System.Xml.Xsl.Xslt.XsltLoader.LoadDocument() +293
       System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(XmlReader reader, Boolean include) +173
    
    4 回复  |  直到 9 年前
        1
  •  5
  •   Gee    15 年前

    使用自定义XmlUrlResolver

    class MyXmlUrlResolver : XmlUrlResolver
        {
            public override Uri ResolveUri(Uri baseUri, string relativeUri)
            {
                if (baseUri != null)
                    return base.ResolveUri(baseUri, relativeUri);
                else
                    return base.ResolveUri(new Uri("http://mypath/"), relativeUri);
            }
        }
    

    并将其用于xslcompiredtransform的加载函数中,

    resolver=new MyXmlUrlResolver();
    xslt.Load(xR,null,resolver);
    
        2
  •  2
  •   David E    15 年前

    我可能忽略了这一点,但是有没有理由不将included.xsl的uri更改为真正的url?这可以在xsl文档中完成,如果您有访问权限,或者使用字符串操作?

        3
  •  2
  •   Kenny Evitt    12 年前

    正如gee的回答所提到的,您需要使用 XmlResolver (其中 XmlUrlResolver 已派生),但如果还重写该方法 GetEntity 您可以以有趣和有趣的方式解析主XSLT文档中的引用。一个故意简单的例子,说明如何解析对 包含XSL :

    public class CustomXmlResolver : XmlResolver
    {
        public CustomXmlResolver() { }
    
        public override ICredentials Credentials
        {
            set { }
        }
    
        public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
        {
            MemoryStream entityStream = null;
    
            switch (absoluteUri.Scheme)
            {
                case "custom-scheme":
    
                    string absoluteUriOriginalString = absoluteUri.OriginalString;
                    string ctgXsltEntityName = absoluteUriOriginalString.Substring(absoluteUriOriginalString.IndexOf(":") + 1);
                    string entityXslt = "";
    
                    // TODO: Replace the following with your own code to load data for referenced entities.
                    switch (ctgXsltEntityName)
                    {
                        case "Included.xsl":
                            entityXslt = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n  <xsl:template name=\"Included\">\n\n  </xsl:template>\n</xsl:stylesheet>";
                            break;
                    }
    
                    UTF8Encoding utf8Encoding = new UTF8Encoding();
                    byte[] entityBytes = utf8Encoding.GetBytes(entityXslt);
                    entityStream = new MemoryStream(entityBytes);
    
                    break;
            }
    
            return entityStream;
        }
    
        public override Uri ResolveUri(Uri baseUri, string relativeUri)
        {
            // You might want to resolve all reference URIs using a custom scheme.
            if (baseUri != null)
                return base.ResolveUri(baseUri, relativeUri);
            else
                return new Uri("custom-scheme:" + relativeUri);
        }
    }
    

    当你装载 MX.XSL 将相关代码更改为以下内容:

    xslt.Load(xpDoc, new XsltSettings(true, true), new CustomXmlResolver());
    

    上面的例子是基于MSDN文章中的信息 Resolving the Unknown: Building Custom XmlResolvers in the .NET Framework .

        4
  •  0
  •   user3175146    9 年前

    我已经成功地使用所有内存进行了转换:

    包含以下内容的xslt包括:

    导入ref=“common.xslt”和 导入ref=“xhtml.xslt”

        private string Transform(string styleSheet, string xmlToParse)
                {
                    XslCompiledTransform xslt = new XslCompiledTransform();
    
                    MemoryResourceResolver resolver = new MemoryResourceResolver();            
    
    
                    XmlTextReader xR = new XmlTextReader(new StringReader(styleSheet));           
    
                    xslt.Load(xR, null, resolver);
    
                    StringWriter sw = new StringWriter();                
    
    
                    using (var inputReader = new StringReader(xmlToParse))
                    {
                        var input = new XmlTextReader(inputReader);
                        xslt.Transform(input,
                                            null,
                                            sw);
                    }
    
                    return sw.ToString();
    
                }     
    
        public class MemoryResourceResolver : XmlResolver
            {
    
                public override object GetEntity(Uri absoluteUri,
                  string role, Type ofObjectToReturn)
                {
                    if (absoluteUri.ToString().Contains("Common"))
                    {
                        return new MemoryStream(Encoding.UTF8.GetBytes("Xml with with common data"));
                    }
    
                    if (absoluteUri.ToString().Contains("Xhtml"))
                    {
                        return new MemoryStream(Encoding.UTF8.GetBytes("Xml with with xhtml data"));
                    }         
    
                    return "";
                }
            }
    

    注意,所有内容都是字符串:样式表、xmltparse和“common”和“xhtml”导入的内容

    推荐文章