2012-01-24 13 views
5

W ramach procesu kompilacji aplikacji internetowej skonfigurowałem arkusze stylów XSLT, które zostaną zbudowane przy użyciu kompilatora Microsoft's xsltc.exe, gdy uruchomimy pełną kompilację. Podczas lokalnego rozwoju działało to świetnie, ponieważ kod jest kompilowany i hostowany w tej samej lokalizacji. Jednak po umieszczeniu tego na serwerze kompilacji pojawiły się problemy.Jak rozpoznać elementy <xsl:import> i <xsl:include> ze względnymi ścieżkami podczas korzystania z xsltc.exe XslCompiledTransforms?

Serwer build będzie kompilacji stylów XSLT jak zrobić lokalnie, ale następnie uruchamia skrypt, który instaluje skompilowany kod do naszego wewnętrznego serwera testowego internetowej. Po przeniesieniu tych plików binarnych z miejsca, w którym zostały skompilowane, względne ścieżki w elementach <xsl:import> i <xsl:include> nie są już poprawnie rozwiązywane, powodując wyjątki, które wyglądają tak, gdy są uruchamiane arkusze stylów XSLT.

Could not find a part of the path 'e:\{PATH}\xslt\docbook\VERSION'. 
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 
    at 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, Boolean useLongPath) 
    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy) 
    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize) 
    at System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn) 
    at System.Xml.Xsl.Runtime.XmlQueryContext.GetDataSource(String uriRelative, String uriBase) 

Oto ogólny pomysł kodu, gdyż stoi teraz:

var xslt = new XslCompiledTransform(); 
xslt.Load(typeof(Namespace.XslTransforms.CompiledXsltStylesheet)); 
xslt.Transform("input.xml", "output.xml"); 

Teraz używam metody XslCompiledTransform.Load() za pomocą jednego parametru „typ”, aby doprowadzić w oparte na xsltc.exe wstępnie skompilowane arkusze stylów XSLT. Mogę powiedzieć ze śledzenia stosu, że platforma .NET używa XmlUrlResolver, aby spróbować rozwiązać faktyczną lokalizację tych zewnętrznych arkuszy stylów, ale nie widzę sposobu na nadpisanie implementacji XmlResolver, w którym mógłbym przekazać nowy baseUri wskazujące, gdzie te arkusze stylów znajdują się na serwerze sieciowym.

Zakładam mogę rozwiązać ten problem nie jest już pre-kompilacji z xsltc.exe i załadowaniem arkuszy stylów XSLT poprzez XmlReaders, ponieważ pozwoli mi korzystać z other XslCompiledTransform.Load() methods które mają parametr, gdzie mogę zapewnić własną implementację XmlResolver. Jednak podoba mi się opcja wstępnej kompilacji do sprawdzania składni i wydajności, więc nie chcę rezygnować, chyba że absolutnie muszę.

Czy istnieje sposób na wykorzystanie xsltc.exe wstępnie skompilować te arkusze stylów XSLT, a jednocześnie zapewnić sposób wyraźne określenie baseUri dla rozdzielczości względnej ścieżki z <xsl:include> i <xsl:import> elementów w czasie wykonywania?

+0

Czy zaimportowane/dołączone arkusze stylów nie są wdrażane razem z plikiem binarnym (do "wewnętrznego serwera sieciowego pomostowego")? –

+0

Są, ale znajdują się w innym katalogu niż miejsce, w którym zostały skompilowane. – Technetium

+1

Jeśli naśladujesz strukturę katalogów serwera WWW pomostowego na serwerze kompilacji (gdzie kompilujesz arkusz stylów), czy to spowoduje dodatnią różnicę? –

Odpowiedz

3

Po dużo grania na około w ten sposób dowiedziałem się, że miałem rację, że podany przeze mnie kod automatycznie używa System.Xml.XmlUrlResolver do rozstrzygania względnych ścieżek w czasie wykonywania. Jednak użycie XmlUrlResolver nie jest związane z System.Xml.XslCompiledTransform, gdy jest umieszczone w plikach binarnych przez xsltc.exe. XmlResolver jest faktycznie wybrany przez właściwość XmlResolver na System.Xml.XmlReaderSettings na System.Xml.XmlReader, która wykonuje transformację w czasie wykonywania. Po ustawieniu własnego niestandardowego XmlResolver na XsltReaderSettings, którego używałem, byłem w stanie kontrolować względną rozdzielczość ścieżki.

Jeśli chcesz zmienić to XmlResolver jak ja, następujący kod może być użyty jako przewodnik:

var customXmlResolver = new SomeCustomXmlResolver(); // Derives from XmlResolver 
var xmlReaderSettings = new XmlReaderSettings { 
    XmlResolver = customXmlResolver 
}; 

var xslt = new XslCompiledTransform(); 
xslt.Load(typeof(Namespace.XslTransforms.CompiledXsltStylesheet)); 

using (var xmlReader = XmlReader.Create("input.xml", xmlReaderSettings)) { 
    using (var xmlWriter = XmlWriter.Create("output.xml")) { 
    xslt.Transform(xmlReader, null, xmlWriter, customXmlResolver); 
    } 
} 

nadal używam xsltc.exe skompilować moje arkuszy stylów XSLT, ale kiedy załadować te skompilowane stylów na serwerze WWW wtrysku SomeCustomXmlResolver przepisuje ścieżki w nadpisanych metodach ResolveUri() i GetEntity(), dzięki czemu można znaleźć pliki odniesienia, które znajdują się w ścieżkach względnych opartych na <xsl:include> i <xsl:import>. Dodatkową korzyścią jest to, że dodając ten sam XmlResolver na końcu metody Transform(), operacje w kodzie XML również będą miały poprawne ścieżki względne.

+0

Musisz być bardzo zdezorientowany. 'XmlReader' w twoim kodzie jest używany tylko do odczytu' "input.xml" '- nie do ładowania arkusza stylów XSLT. Kiedy wykonywana jest metoda 'xslt.Load()', nie ma ona żadnego odniesienia do żadnego 'XmlReader' w ogóle. Jeśli jest jakiś problem z wykonaniem 'xsl: import' i' xsl: include', to metoda 'Load()' podnosi wyjątek - i tak się nie dzieje w twoim przypadku - bez użycia jakiegokolwiek odniesienia do 'XmlReader'a '. –

+0

Nie jestem zdezorientowany, Dimitre. Mam działający kod i przechodząc przez debugger, wyraźnie widzę, że względne ścieżki elementów XSL są przekazywane przez XmlResolver, który przypiszę w czasie wykonywania. '', '', ' ', itp. To jest właściwa odpowiedź. – Technetium

+0

Technetium: Masz co najmniej jeden z zaimportowanych/dołączonych arkuszy stylów używa funkcji 'document()' ze względnym lub pustym adresem URL - to jest prawdziwy problem, którego nigdy nie wyjaśniłeś. Jeśli żaden z zaimportowanych/dołączonych arkuszy stylów nie odwołuje się do funkcji 'document()', nie byłoby żadnego problemu. Znajdę trochę wolnego czasu następnego dnia, aby zbudować przykłady, które to potwierdzają. –

0

Nie wiem, czy to łamie swój system, ale jak o zamiast

  1. kompilacji z xsltc.exe
  2. wdrażania binarne
  3. załadowanie binarnie z this Load()

ty

  1. wdrożyć arkusze stylów, jednak wiele z nich jest wymagana z dyrektywami import/include
  2. obciążenie głównym arkusza stylów z this Load(), określając rozpoznawania nazw dla import/incldue

Okazuje się nadal będziesz uzyskać korzyść „skompilowany” arkusz stylów, przynajmniej w czasie wykonywania.

+0

Z pewnością mogę uzyskać dostęp do arkuszy stylów XSLT bezpośrednio z systemu plików na serwerze WWW. Nawet z głównym arkuszem stylów skompilowanym przy pomocy xsltc.exe, MUSZĄ istnieć, aby transformacja mogła działać. Jednakże, chyba że jest coś, czego nie rozumiem w odniesieniu do określonej metody Load(), która będzie kompilować arkusze stylów za każdym razem, gdy zostaną załadowane w czasie wykonywania, co było jedną z rzeczy, których starałem się uniknąć ze względu na wydajność. Oznaczałoby to również, że musiałbym obniżyć walidację składni do statusu testu jednostkowego. – Technetium

+0

Och, myślałem, że plik DLL był ładowany raz, na początku. Tak, to nie zadziała. –

2

Czy istnieje sposób użycia xsltc.exe do wstępnej kompilacji arkuszy stylów XSLT, , ale nadal zapewnia sposób jawnego określenia baseUri dla względnej rozdzielczości ścieżki <xsl:include> i <xsl:import> w środowisku wykonawczym?

spróbuje użyć:

XslCompiledTransform.CompileToType()

Jednym z argumentów, że ta metoda statyczna akceptuje to:

XmlResolver stylesheetResolver 
+0

Ach tak! Wygląda to bardzo obiecująco. Odpalę i oznaczę to jako poprawną odpowiedź, gdy tylko będę miał szansę zweryfikować. Dokumentacja msdn stwierdza nawet, że 'xsltc.exe' jest otoką, więc najważniejsze pozostaje to, czy 'XmlResolver' buforuje baseUri podczas kompilacji lub czy' XmlResolver' jest uruchamiany ponownie podczas działania (co jest zarówno tym, czego chcę i na podstawie na śladzie stosu, co zakładam, że się wydarzy). – Technetium

+0

@ Technetium: Myślę, że nie ma sensu naprawiać resolwera tak wcześnie podczas kompilacji. To powinno być tym, o co prosisz. –

+0

Tak jak w szkole średniej, działałem przedwcześnie, ponieważ byłem tak podekscytowany. ** W rzeczywistości jest to niepoprawna odpowiedź. ** Podczas gdy Dimitre ma rację, XmlResolver zastosowany w tej metodzie służy do rozpoznawania elementów '' i '' podczas kompilowania arkusza stylów XSLT, nie jest ponownie używany w czasie wykonywania . XmlResolver używany w czasie wykonywania wybierany jest przez XmlReaderSettings źródłowego pliku XML. Zobacz moją odpowiedź dla dalszych szczegółów. – Technetium

Powiązane problemy