2012-01-24 22 views
5

Là một phần của quá trình xây dựng ứng dụng web của chúng tôi, tôi đã thiết lập các bản định kiểu XSLT của chúng tôi để được xây dựng với trình biên dịch Microsoft's xsltc.exe bất cứ khi nào chúng tôi chạy một bản dịch đầy đủ. Trong quá trình phát triển địa phương, điều này đã làm việc rất tốt, vì mã được biên dịch và lưu trữ trong cùng một vị trí. Tuy nhiên, một khi điều này đã được đặt trên máy chủ xây dựng, vấn đề phát sinh.Làm cách nào để giải quyết các yếu tố <xsl:import> và <xsl:include> có đường dẫn tương đối khi sử dụng xsltc.exe XslCompiledTransforms?

Máy chủ xây dựng sẽ biên dịch biểu định kiểu XSLT giống như tôi làm cục bộ, nhưng sau đó tập lệnh chạy triển khai mã được biên dịch đến máy chủ web dàn dựng nội bộ của chúng tôi. Khi các tệp nhị phân này đã di chuyển từ nơi chúng được biên dịch, các đường dẫn tương đối trong các phần tử <xsl:import><xsl:include> không còn giải quyết chính xác nữa, khiến các ngoại lệ trông như thế này khi các bảng định kiểu XSLT được chạy.

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) 

Dưới đây là một ý tưởng chung của các mã như nó đứng bây giờ:

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

Ngay bây giờ tôi đang sử dụng phương pháp XslCompiledTransform.Load() với một tham số duy nhất 'Loại' để mang lại trong các bản định kiểu XSLT được biên dịch trước dựa trên xsltc.exe. Tôi có thể nói từ dấu vết ngăn xếp rằng khuôn khổ .NET đang sử dụng XmlUrlResolver để cố gắng giải quyết vị trí thực tế của các biểu định kiểu bên ngoài này, nhưng tôi không thấy cách nào để cung cấp một triển khai ghi đè XmlResolver mà tôi có thể chuyển vào một baseUri trỏ đến nơi các bảng định kiểu này xuất hiện trên máy chủ web. Tôi giả sử tôi có thể giải quyết điều này bằng cách không còn biên dịch trước bằng xsltc.exe và tải bản định kiểu XSLT qua XmlReaders, vì điều đó sẽ cho phép tôi sử dụng other XslCompiledTransform.Load() methods có tham số nơi tôi có thể cung cấp triển khai XmlResolver của riêng mình. Tuy nhiên, tôi thích tùy chọn biên dịch trước để xác thực cú pháp và hiệu suất, vì vậy tôi không muốn từ bỏ nó trừ khi tôi hoàn toàn phải làm vậy.

Có cách nào để sử dụng xsltc.exe để pre-biên dịch các stylesheets XSLT, nhưng vẫn cung cấp một cách để nêu một cách rõ ràng baseUri cho tương độ phân giải con đường của <xsl:include><xsl:import> yếu tố trong thời gian chạy?

+0

Các biểu định kiểu được nhập/bao gồm không được triển khai cùng với tệp nhị phân (đến 'máy chủ web phân trang nội bộ')? –

+0

Chúng có, nhưng chúng nằm trong một thư mục khác với nơi chúng được biên dịch. – Technetium

+1

Nếu bạn bắt chước cấu trúc thư mục của máy chủ web dàn dựng trên máy chủ xây dựng (nơi bạn đang biên dịch biểu định kiểu), điều đó có tạo nên sự khác biệt tích cực không? –

Trả lời

3

Sau một nhiều, vui chơi xung quanh với điều này, tôi phát hiện ra rằng tôi đã đúng rằng mã tôi đã cung cấp tự động sử dụng số System.Xml.XmlUrlResolver để giải quyết các đường dẫn tương đối <xsl:include><xsl:import> tương đối tại thời gian chạy. Tuy nhiên, việc sử dụng XmlUrlResolver không bị ràng buộc vào System.Xml.XslCompiledTransform khi nó được đặt trong một nhị phân bởi xsltc.exe. XmlResolver thực sự được chọn bởi thuộc tính XmlResolver trên System.Xml.XmlReaderSettings trên System.Xml.XmlReader thực hiện phép biến đổi tại thời gian chạy. Khi tôi đã đặt XmlResolver tùy chỉnh của riêng mình trên XsltReaderSettings mà tôi đã sử dụng, tôi đã có thể kiểm soát độ phân giải đường dẫn tương đối.

Nếu bạn muốn ghi đè XmlResolver này như tôi đã làm, các mã sau đây có thể được sử dụng như một hướng dẫn:

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

tôi vẫn đang sử dụng xsltc.exe để biên dịch stylesheets XSLT của tôi, nhưng khi tôi tải các stylesheets biên soạn trên máy chủ web, tiêm SomeCustomXmlResolver ghi lại các đường dẫn trong các phương pháp ResolveUri()GetEntity() được ghi đè để các tệp tham chiếu nằm trong các đường dẫn tương đối dựa trên <xsl:include><xsl:import>. Như một phần thưởng thêm, bằng cách thêm cùng một XmlResolver vào cuối phương thức Transform(), các hoạt động document() trong XML cũng sẽ có đường dẫn tương đối được giải quyết chính xác.

+0

Bạn phải rất bối rối. 'XmlReader' trong mã của bạn chỉ được sử dụng để đọc' "input.xml" '- không phải để tải biểu định kiểu XSLT. Khi phương thức 'xslt.Load()' được thực hiện, nó không có tham chiếu đến bất kỳ 'XmlReader' nào cả. Nếu có bất kỳ vấn đề nào với việc thực hiện 'xsl: import' và' xsl: include', phương thức 'Load()' sẽ đưa ra một ngoại lệ - và điều này không xảy ra trong trường hợp của bạn - mà không sử dụng bất kỳ tham chiếu nào đến 'XmlReader '. –

+0

Tôi không nhầm lẫn Dimitre. Tôi có mã làm việc, và bước qua một trình gỡ rối tôi có thể thấy rõ các đường dẫn tương đối của các phần tử XSL này được truyền qua XmlResolver mà tôi gán vào thời gian chạy. '', '', ' ', vv Đây là câu trả lời đúng. – Technetium

+0

Technetium: Bạn có ít nhất một trong các bảng định kiểu được nhập/bao gồm sử dụng hàm 'document()' với URL tương đối hoặc trống - đây là vấn đề thực sự mà bạn chưa bao giờ giải thích. Nếu không có bảng định kiểu được nhập/bao gồm nào tham chiếu hàm 'document()', thì sẽ không có vấn đề gì cả. Tôi sẽ tìm thấy một số thời gian rảnh trong ngày hôm sau để xây dựng các ví dụ chứng minh điều này. –

0

Tôi không biết nếu điều này phá vỡ hệ thống của bạn, nhưng làm thế nào về thay vì

  1. biên soạn với xsltc.exe
  2. triển khai nhị phân
  3. tải nhị phân với this Load()

bạn

  1. triển khai các stylesheets, tuy nhiên nhiều người được yêu cầu với import/include chỉ
  2. tải stylesheet chính với this Load(), quy định cụ thể giải quyết cho import/incldue

Có vẻ bạn vẫn sẽ nhận được những lợi ích của một "biên soạn" biểu định kiểu, ít nhất là trong thời gian chạy.

+0

Chắc chắn tôi có thể truy cập các bảng định kiểu XSLT này trực tiếp từ hệ thống tệp trên máy chủ web. Ngay cả với biểu định kiểu chính được biên dịch bằng xsltc.exe, chúng sẽ CÓ ở đó để biến đổi thành hàm. Tuy nhiên, trừ khi có điều gì đó tôi không hiểu về phương thức Load() mà bạn đã chỉ định, nó sẽ biên dịch các bảng định kiểu mỗi khi chúng được tải vào thời gian chạy, đó là một trong những thứ tôi đang cố tránh vì lý do hiệu suất. Điều đó cũng có nghĩa là tôi phải làm giảm xác nhận cú pháp thành trạng thái Kiểm tra đơn vị. – Technetium

+0

Ồ, tôi nghĩ rằng các DLL đã được nạp một lần, trong đầu. Yeah, nó sẽ không hoạt động. –

2

Có cách nào để sử dụng xsltc hay không.exe để biên dịch trước các bản định kiểu XSLT này, nhưng vẫn cung cấp cách để khai báo rõ ràng baseUri cho tương đối độ phân giải đường dẫn của các yếu tố <xsl:include><xsl:import> khi chạy?

Cố gắng sử dụng:

XslCompiledTransform.CompileToType()

Một trong những lập luận rằng phương pháp tĩnh này chấp nhận là:

XmlResolver stylesheetResolver 
+0

À vâng! Điều này có vẻ rất hứa hẹn. Tôi sẽ cung cấp cho nó một đi, và cờ này là câu trả lời đúng một khi tôi có một cơ hội để xác minh. Tài liệu msdn thậm chí nói rằng 'xsltc.exe' là một wrapper xung quanh điều này, do đó, câu hỏi lớn vẫn còn là nếu 'XmlResolver' lưu trữ baseUri trong thời gian biên dịch hoặc nếu' XmlResolver' được chạy lại trong thời gian chạy (đó là cả những gì tôi muốn và, dựa trên khi theo dõi ngăn xếp, những gì tôi giả định sẽ xảy ra). – Technetium

+0

@Technetium: Tôi nghĩ rằng không có ý nghĩa khi sửa chữa trình giải quyết sớm như vậy lúc biên dịch. Đây sẽ là những gì bạn đang sau. –

+0

Như tôi đã học ở trường trung học, tôi đã hành động sớm ở đây vì tôi rất phấn khích. ** Đây thực sự là câu trả lời sai. ** Trong khi Dimitre đúng là XmlResolver được cung cấp trong phương thức này được sử dụng để giải quyết các phần tử '' và '' khi biểu định kiểu XSLT được biên dịch, nó không được sử dụng lại vào thời gian chạy . XmlResolver được sử dụng tại thời gian chạy được chọn bởi XmlReaderSettings của tệp XML nguồn. Xem câu trả lời của tôi để biết thêm chi tiết. – Technetium