2009-06-15 15 views
5

.NET 2.0/VS2005XSLを解決するには、文字列からXSLをロードする変換が含まれていますか?

私は、XSL変換を実行するためにXslCompiledTransformクラスを使用しようとしています。私は「メインを読み込むことができれば、今

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

Main.xsl:私は<xsl:include>声明の形で他への参照を含む第1のどの2つのXSLファイルを、持っています.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\フォルダの "Included.xsl"を検索するため、失敗します。明らかに、XmlResolverは入力XSLとして文字列を受け取るだけなので、相対URLを解決することはできません。この方向で

私の努力は次のようになります。

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

私が含まれるXSLファイルを参照Streamを得るために、XmlUrlResolverのResolveUriメソッドを使用しようとしましたが、どのようにと混乱していていますこのストリームを使用するIOWは、どのように私はMain.xslたXmlReaderに加えて、このストリームを使用するようにXslCompiledTransformオブジェクトを教えてください:

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

あなたの質問に似た何かが働いていて、MSDNの記事「Unknownの解決:.NET FrameworkでのカスタムXmlResolversの構築」(http://msdn.microsoft.com/en-us/)ライブラリ/ aa302284.aspx) - これは非常に有望な解決策を提供するようです。 –

答えて

2

私はおそらく明らかに行方不明ですが、あなただけの真のURLであることをIncluded.xslのURIを変更しない理由があります?これは、アクセス権を持っているか、そうでなければ文字列操作を使用している場合は、XSLドキュメントで行うことができますか?ジーの答えが言及したよう

+0

David:返事をありがとう。その理由は、一般的なルールとして、アプリケーション内のどこにでもパスをハードコードすることができないためです。この場合、私の最後の手段になります。 ;-) – Cerebrus

+0

私はそれが避けられないと確信しています。このストリームの例は、Include.xslと同じ物理的な場所からMain.xslをロードしているために機能します。したがって、文字列操作に戻るには、URIにRequest.PhysicalApplicationPathを追加するだけです。 それ以外の場合、コードはInclude.xslの検索場所をどのように認識しますか?文字列から来るときに余分なポインタが必要になるでしょう Tnx –

+0

Hmmm ...私はカスタムXmlUrlResolver(よりクリーンな方法)を派生させることでそれを行うことができませんでした。時間の制約のために、私はそれをストリング操作で行う必要があります。アイデアをありがとう。 – Cerebrus

5

あなたはXmlUrlResolverが既に導出さXmlResolver(そのカスタムを使用したい、

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

Karthik:返信いただきありがとうございます。これは私が現在追求している方向です。カスタムのXmlUrlResolverの "http:// mypath /"部分をハードコーディングしないようにする方法があるのだろうかと思います。何か案は ? – Cerebrus

+0

設定可能なパラメータでも、同じサーバーでホストされている場合はServer.MapPathを使用します。ところで、Main.xslはどうやって入手できますか? HTTPパスにアクセスすることによって? – Gee

2

、カスタム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); 
     } 
    } 

を使用し、XslCompiledTransformではのロード機能でそれを使用します)でも、メソッドGetEntityをオーバーライドすると、プライマリXSLTドキュメントの参照を楽しく興味深い方法で解決できます。あなたがメインをロードすると

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

:あなたはIncluded.xslへの参照を解決することができる方法の故意簡単な例。次に、関連するコードを変更したいのxsl文書:

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

上記の例では、私がピックアップされたMSDNの記事Resolving the Unknown: Building Custom XmlResolvers in the .NET Frameworkでの情報に基づいていました。

0

私は既にメモリ内のすべてを使用して変換を行うと成功を持っている:

以下を含むXSLTが含ま持つ:

輸入のhref = "Common.xslt" と 輸入の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 ""; 
      } 
     } 

注:スタイルシート、xmlToParseと「共通」と「てXhtml」輸入の内容

関連する問題