2017-08-06 67 views
1

我想驗證我對Saxon的XSLT對象和併發性的理解。併發問題 - .NET上的Saxon 9.6,XSLT和自定義XmlResolver和CollectionUriResolvers

基本上,我需要自定義的解析器來將特定於請求的數據返回給變換,而目前,我爲每個請求的每個變換創建瞭解析器的新實例。我已經有了一個來自另一個請求的數據的早期報告,這是一個重要的問題。


使用撒克遜9.6.0.6 HE上.NET 4.6(C#),視窗7 /服務器2012

我的代碼可以爲許多併發請求執行許多不同的共享變換。撒克遜編譯的XSLT是性能必不可少的。目前,代碼是多線程的(在適當的情況下使用TPL和異步),並且不使用鎖定(並且如果可能的話,希望避免這種情況)。

我偶爾會發現數據在轉換輸出請求(即可能是併發問題)中被錯誤地「泄漏」。我不確定這是否與自定義XmlResolver或自定義CollectionUriResolver的行爲相關聯。我在等待更多信息。我還沒有能夠重新創建這個問題(如果可以的話,仍然可以在這個版本上發佈更新)。

我們的轉換使用fn:doc和fn:collection。

代碼在應用程序啓動時預編譯所有可能的轉換。這些可執行文件是共享的。

對於事務中的給定轉換,我的代碼通過編譯的可執行文件的.Load()調用創建一個XsltTransformer對象。這似乎創建了一個新的對象,看着9.6 HE代碼(這是我所期望的)。

接下來,我的代碼創建了一個自定義XmlResolver和CollectionUriResolver的新實例(尚未轉移到CollectionFinder,但認爲這可能以相同方式運行),並且這些實例都填充了適當的特定於請求的文檔/值/等進入變換。

這兩個解析器的生命週期只有一次XSLT執行 - 它們不會被重用。

我們與XsltTransform對象我知道如何的唯一途徑解析器相關聯:

Saxon.Api.XsltTransformer transform = executable.Load(); 
transform.InitialContextNode = sourceData; 
transform.Implementation.getConfiguration(). 
    setCollectionURIResolver(collectionResolver); 
transform.InputXmlResolver = inputResolver; 

撒克遜代碼,它看起來像輸入解析器是基於實例的,因此不共享(最終出現生活在Controller類中,如下所示,當通過Load()創建XsltTransformer時,它本身就是一個新實例)。

public XmlResolver InputXmlResolver 
{ 
    set 
    { 
     controller.setURIResolver(new DotNetURIResolver(value)); 
    } 
} 

不過,我擔心的是,配置數據可以共享,並在設定的配置對象的集合解析器(在CollectionFinder似乎是相同的),我們可以有我們的併發問題。

什麼是正確的方式來實現我所追求的結果 - 我們的自定義解析器能夠響應特定於請求的行爲?我可以在每個變換中使用一對實例和請求特定數據嗎?還是必須通過請求共享解析器(可能將請求ID注入到變換中以形成傳遞給解析器的URI的一部分)?

稍向更新 似乎可以直接設置CollectionURIResolver在兩個控制器(「執行」),或配置,並且這些在存儲器明顯不同的對象:

transform.Implementation.setCollectionURIResolver(collectionResolverOne);   
transform.Implementation.getConfiguration(). 
    setCollectionURIResolver(collectionResolverTwo); 

然而,在運行時,它是被調用的配置的解析器(在上面的例子中爲collectionResolverTwo)。我不確定控制器的副本服務的目的。

此外,看起來配置數據確實是共享的,因爲如果我從同一個可執行文件創建第二個轉換器並將它設置爲配置級別的集合解析器,則會更新第一個轉換器使用的解析器。

所以 - 我想我已經找到了我的問題 - 我現在只需要知道在我需要集合解析器來解決每個請求的唯一集合的情況下做的正確事情(例如,一個請求可能有一個特定集合中有五個條目,另一個可能有兩個)。

回答

1

我認爲在解釋你的問題時,你本質上已經解決了它。 Saxon中的配置對象(在API級別支持處理器)是共享的,並且在任何初始化之後,強烈建議不要使用諸如setURIResolver()之類的方法更改其狀態,因爲這些更改會影響工作中的進行中未定義的方式。

撒克遜的API對象和內部對象具有一一對應關係,並且內部對象沒有100%封裝,因爲有些用戶需要訪問更加貼心的功能。在Java世界中,還有JAXP類在概念上相似,但僅限於XSLT 1.0功能。的對應關係是:

約撒克遜環境作爲一個整體共享信息:

API:處理器內部:配置JAXP:的TransformerFactory

含有可重複使用XSLT編譯器選擇編譯樣式表:

API:XsltCompiler 內部:CompilerInfo JAXP:沒有等效

甲編譯的樣式表,其可以(在多線程和同時地)重複執行

API:XsltExecutable 內部:Executable/PreparedStylesheet JAXP:模板

單一的轉化,轉化使用一個樣式表一個源文件:

API:XsltTransformer 內部:控制器JAXP:變壓器

在撒克遜某些配置選項只能在配置級例如,可用的整理URI集合在此級別定義,並且不能從一個轉換到另一個轉換。

但是,URIResolvers通常可以在XsltTransformer/Controller級別定義。它們也可以設置在處理器/配置上,但如果您想要始終使用相同的設置,則這只是默認設置。在你的情況下,你應該將它們設置在控制器級別。

+0

謝謝!我認爲我在這裏遇到的問題是由於9.6.0.6不能按預期工作。升級到9.8.0.2解決了問題 - 解析器不按預期共享。 – user426445

+0

但是 - 有一個意想不到的行爲。當我在Controller上設置了自定義URIResolver和CollectionURIResolver時,對fn:doc的調用按預期使用自定義URIResolver,*但*,由定製CollectionURIResolver解析的任何URI都由與Configuration對象關聯的URIResolver加載,而不是Controller 。你可以在CollectionURIResolverWrapper代碼中看到這個。 – user426445

+0

我已更新爲使用CollectionFinder界面。似乎要做的伎倆。 – user426445