2009-06-15 47 views
5

NET 2.0/VS2005Cách giải quyết XSL bao gồm trong một phép biến đổi tải XSL từ một chuỗi?

Tôi cố gắng để sử dụng lớp XslCompiledTransform để thực hiện một chuyển đổi XSL. Tôi có hai tập tin XSL, là người đầu tiên trong số đó bao gồm một tham chiếu đến khác theo hình thức của một câu lệnh <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> 

Bây giờ, Nếu tôi có thể nạp "Main .xsl" nộp chính nó như là một URI, mã chuyển đổi của tôi sẽ là đơn giản như:

// 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(); 
} 

vấn đề là tôi nhận được nội dung của file Main.xsl như là một chuỗi và cần phải nạp chuỗi như một XmlReader/IXpathNavigable . Đây là hạn chế cần thiết tại thời điểm này. Khi tôi cố gắng làm tương tự bằng cách sử dụng XmlReader/XpathDocument, nó không thành công vì mã tìm kiếm "Included.xsl" trong thư mục C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\! Rõ ràng, XmlResolver không thể giải quyết URL tương đối vì URL này chỉ nhận được chuỗi là XSL đầu vào.

nỗ lực của tôi theo hướng này trông giống như:

// 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(); 
} 

Tôi đã cố gắng sử dụng các phương pháp ResolveUri của XmlUrlResolver để có được một Stream tham khảo các tập tin XSL để được bao gồm, nhưng bối rối như thế nào để sử dụng Luồng này. IOW, làm thế nào để tôi nói với đối tượng XslCompiledTransform sử dụng dòng này ngoài các 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?? 


Any help is appreciated rất nhiều. Xin lôi vi bai đăng dai!

Đối với các bạn tham khảo, các ngoại lệ StackTrace trông như thế này:

[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 
+0

Tôi đang làm việc trên một cái gì đó tương tự như những gì câu hỏi của bạn dường như yêu cầu và tôi tìm thấy một bài viết MSDN - [Giải quyết các Unknown: Xây dựng Custom XmlResolvers trong. NET Framework] (http://msdn.microsoft.com/en-us/ library/aa302284.aspx) - dường như cung cấp một giải pháp rất hứa hẹn. –

Trả lời

2

Tôi lẽ thiếu rõ ràng nhưng có một lý do bạn không chỉ cần thay đổi URI của Included.xsl là một URL đúng ? Điều này có thể được thực hiện trong tài liệu XSL nếu bạn có quyền truy cập hoặc sử dụng thao tác chuỗi không?

+0

David: Cảm ơn bạn đã trả lời. Lý do là tôi không thể mã hóa cứng bất kỳ đường dẫn nào trong ứng dụng, như một quy tắc chung. Trong trường hợp này, đó sẽ là phương sách cuối cùng của tôi. ;-) – Cerebrus

+0

Tôi không chắc chắn rằng nó có thể tránh được. Ví dụ về luồng hoạt động vì bạn đang tải Main.xsl từ cùng một vị trí thực tế như Include.xsl. Do đó trở lại thao tác chuỗi bạn chỉ có thể thêm Request.PhysicalApplicationPath vào URI Nếu không, mã sẽ biết nơi cần tìm Include.xsl như thế nào? Nó luôn luôn sẽ cần thêm con trỏ như bạn đang đến từ một chuỗi Tnx –

+0

Hmmm ... Tôi đã không thể làm điều đó bằng cách bắt nguồn một XmlUrlResolver tùy chỉnh (đó là cách sạch hơn). Bởi vì các ràng buộc về thời gian, tôi sẽ phải thực hiện nó thông qua thao tác String. Cảm ơn ý tưởng. – Cerebrus

5

Sử dụng một XmlUrlResolver tùy chỉnh

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); 
     } 
    } 

Và sử dụng nó trong chức năng tải của XslCompiledTransform,

resolver=new MyXmlUrlResolver(); 
xslt.Load(xR,null,resolver); 
+0

Karthik: Cảm ơn bạn đã trả lời. Đây là hướng tôi đang theo đuổi. Tôi tự hỏi nếu có một cách để tránh khó mã hóa phần "http: // mypath /" trong XmlUrlResolver tùy chỉnh. Bất kỳ ý tưởng? – Cerebrus

+0

Đó có thể là một tham số có thể cấu hình hoặc nếu nó được lưu trữ trên cùng một máy chủ sử dụng Server.MapPath. BTW, Làm thế nào để bạn có được Main.xsl? Bằng cách truy cập đường dẫn HTTP? – Gee

2

Như câu trả lời Gee của đề cập đến, bạn muốn sử dụng một tùy chỉnh XmlResolver (trong đó XmlUrlResolver đã được bắt nguồn), nhưng nếu bạn cũng ghi đè phương thức GetEntity, bạn có thể giải quyết các tham chiếu trong tài liệu XSLT chính theo những cách thú vị và thú vị. Một ví dụ cố tình đơn giản về cách bạn có thể giải quyết các tài liệu tham khảo để Included.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); 
    } 
} 

Khi bạn tải các Main.xsl chứng từ bạn muốn thay đổi mã có liên quan như sau:

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

Ví dụ trên được dựa trên thông tin tôi nhặt lên trong bài viết MSDN Resolving the Unknown: Building Custom XmlResolvers in the .NET Framework.

0

Tôi đã có thành công với việc biến đổi sử dụng tất cả trong bộ nhớ:

Có một XSLT chứa những điều sau đây bao gồm:

nhập khẩu href = "Common.xslt" và nhập khẩu href = "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 ""; 
      } 
     } 

Lưu ý rằng hoàn toàn tất cả nội dung là như dây đàn: stylesheet, xmlToParse và nội dung của nhập khẩu "XHTML" "chung"

Các vấn đề liên quan