2013-04-18 36 views
5

Trong Delphi XE2, tôi đang làm một biến đổi xslt trên một tệp XML nhận được để loại bỏ tất cả các thông tin không gian tên.
Vấn đề: Nó thay đổiNgăn biến đổi XSLT chuyển đổi XML utf-8 thành utf-16?

<?xml version="1.0" encoding="utf-8"?> 

vào

<?xml version="1.0" encoding="utf-16"?> 

Đây là XML mà tôi nhận lại từ máy chủ Exchange:

<?xml version="1.0" encoding="utf-8"?> 
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> 
<s:Header> 
<h:ServerVersionInfo MajorVersion="14" MinorVersion="0" MajorBuildNumber="722" MinorBuildNumber="0" Version="Exchange2010" xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"/> 
</s:Header> 
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
<m:ResolveNamesResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> 
<m:ResponseMessages> 
<m:ResolveNamesResponseMessage ResponseClass="Success"> 
<m:ResponseCode>NoError</m:ResponseCode> 
<m:ResolutionSet TotalItemsInView="1" IncludesLastItemInRange="true"> 
<t:Resolution> 
<t:Mailbox> 
<t:Name>developer</t:Name> 
<t:EmailAddress>[email protected]</t:EmailAddress> 
<t:RoutingType>SMTP</t:RoutingType> 
<t:MailboxType>Mailbox</t:MailboxType> 
</t:Mailbox> 
<t:Contact> 
<t:Culture>nl-NL</t:Culture> 
<t:DisplayName>developer</t:DisplayName> 
<t:GivenName>developer</t:GivenName> 
<t:EmailAddresses> 
<t:Entry Key="EmailAddress1">SMTP:[email protected]</t:Entry> 
</t:EmailAddresses> 
<t:ContactSource>ActiveDirectory</t:ContactSource> 
</t:Contact> 
</t:Resolution> 
</m:ResolutionSet> 
</m:ResolveNamesResponseMessage> 
</m:ResponseMessages> 
</m:ResolveNamesResponse> 
</s:Body> 
</s:Envelope> 

Đây là chức năng mà loại bỏ các thông tin không gian tên:

Uses 
    MSXML2_TLB; // IXMLDOMdocument 

class function TXMLHelper.RemoveNameSpaces(XMLString: String): String; 
const 
    // An XSLT script for removing the namespaces from any document. 
    // From http://wiki.tei-c.org/index.php/Remove-Namespaces.xsl 
    cRemoveNSTransform = 
    '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">' + 
    '<xsl:output method="xml" indent="no"/>' + 

    '<xsl:template match="/|comment()|processing-instruction()">' + 
    ' <xsl:copy>' + 
    '  <xsl:apply-templates/>' + 
    ' </xsl:copy>' + 
    '</xsl:template>' + 

    '<xsl:template match="*">' + 
    ' <xsl:element name="{local-name()}">' + 
    '  <xsl:apply-templates select="@*|node()"/>' + 
    ' </xsl:element>' + 
    '</xsl:template>' + 

    '<xsl:template match="@*">' + 
    ' <xsl:attribute name="{local-name()}">' + 
    '  <xsl:value-of select="."/>' + 
    ' </xsl:attribute>' + 
    '</xsl:template>' + 

    '</xsl:stylesheet>'; 

var 
    Doc, XSL: IXMLDOMdocument2; 
begin 
    Doc := ComsDOMDocument.Create; 
    Doc.ASync := false; 
    XSL := ComsDOMDocument.Create; 
    XSL.ASync := false; 
    try 
    Doc.loadXML(XMLString); 
    XSL.loadXML(cRemoveNSTransform); 
    Result := Doc.TransFormNode(XSL); 
    except 
    on E:Exception do Result := E.Message; 
    end; 
end; { RemoveNameSpaces } 

Nhưng sau này, nó đột nhiên một tài liệu utf-16:

<?xml version="1.0" encoding="UTF-16"?> 
<Envelope> 
[snip] 
</Envelope> 

Sau Googling "xsl utf-8 utf-16" Tôi đã thử nhiều điều:

  • Thay đổi dòng (ví dụ Output DataTable XML in UTF8 rather than UTF16)

    <xsl:output method="xml" indent="no"> 
    

    vào một trong hai:

    <xsl:output method="xml" encoding="utf-8" indent="no"/> 
    <xsl:output method="xml" encoding="utf-8"/> 
    <xsl:output encoding="utf-8"/> 
    

    Đó không làm việc.
    (Nó sẽ là giải pháp tối ưu, theo http://www.xml.com/pub/a/2002/09/04/xslt.html "Thuộc tính mã hóa thực sự làm nhiều hơn thêm một tuyên bố mã hóa các tài liệu kết quả, nó nói với bộ xử lý XSLT để viết ra kết quả bằng cách sử dụng mã hóa đó.")

  • Thay đổi dòng (ví dụ XslCompiledTransform uses UTF-16 encoding)

    <xsl:output method="xml" indent="no"/> 
    

    vào

    <xsl:output method="xml" omit-xml-declaration="yes" indent="no" /> 
    

    mà lá ra thẻ xml bắt đầu, nhưng nếu tôi sau đó chỉ cần pr epend

    <?xml version="1.0" encoding="utf-8"?> 
    

    Tôi sẽ mất các ký tự vì không có chuyển đổi utf thực tế được thực hiện.

  • IXMLDOMdocument2 không có một tài sản

Bất kỳ ý tưởng làm thế nào để sửa lỗi này Encoding?

chú/nền:

  • Nếu vẫn thất bại có lẽ vẫn là tùy chọn để thay đổi dữ liệu XML utf-16 để utf-8, nhưng đó là một cách tiếp cận hoàn toàn khác nhau.

  • Tôi đang cố gắng làm mọi thứ utf-8 vì tôi đang kết nối với máy chủ Exchange qua EWS và đặt tiêu đề yêu cầu http thành utf-16 không hoạt động: Exchange cho tôi biết rằng văn bản kiểu nội dung '/xml; charset = utf-16 'không phải là kiểu mong đợi' text/xml; charset = utf-8 '.EWS trả về utf-8 (xem bắt đầu bài đăng).

+2

@Gserg cảm ơn chỉnh sửa định dạng, tôi đang vật lộn với các khối mã trong dấu đầu dòng. –

Trả lời

1

Để sử dụng IXMLDocument trong bạn gốc mã, nó sẽ giống như thế này:

var 
    iInp, iOtp, iXsl: IXMLDocument; 
    Utf8: UTF8String; 
begin 
    iInp := LoadXMLData(XMLString); 
    iXsl := LoadXMLData(cRemoveNSTransfrom); 
    iOtp := NewXMLDocument; 
    iInp.Node.TransformNode(iXsl.Node,iOtp); 
    iOtp.SaveToXML(Utf8); 
end 

Bây giờ biến UTF8 nên chứa XML chuyển trong mã UTF-8, Nếu bạn muốn lưu vào dòng/tập tin, thay thế SaveToXML bởi

iOtp.Encoding := 'UTF-8'; 
    iOtp.SaveToFile(....); 
2

Vấn đề là việc sử dụng các phương pháp transformNode, nó sẽ trả về một chuỗi và với MSXML một chuỗi như là UTF-16 được mã hóa. Vì vậy, bạn cần tạo một tài liệu MSXML DOM trống cho kết quả và sử dụng the transformNodeToObject method, chuyển tài liệu DOM trống làm đối số thứ hai, sau đó bạn có thể lưu tài liệu kết quả vào tệp hoặc luồng và mã hóa phải được chỉ định trong chỉ thị xsl:output .

+0

Tôi muốn nói rằng DOM được triển khai thực hiện bằng cách sử dụng UTF-16 do đó kết quả của phép biến đổi trong tài liệu DOM đích cũng sẽ được mã hóa theo UTF-16. Mã hóa mỗi se phải là một nhiệm vụ cho bộ lọc đầu vào/đầu ra, vì vậy tôi mong đợi nó là cần thiết để gọi ví dụ. 'iXMLDocument.SaveToXML (AUTF8String)' – pf1957

+0

MSXML không có phương thức 'SaveToXML'. Nó có một phương thức có tên là 'save' trên các tài liệu DOM và đề xuất của tôi là sử dụng phương thức đó trên một tài liệu DOM đã được tạo ra rỗng và sau đó được truyền vào phương thức' transformNodeToObject'. Bằng cách đó, nếu bạn lưu vào một tệp hoặc luồng, mã hóa phải như dự định. Điều đó là không thể nếu bạn sử dụng 'transformNode'. –

+0

Tôi biết. Tôi đã từng không gọi MSXML trực tiếp nhưng thông qua 'IXMLDocument'/'IXMLNode'. Có quá nhiều phương thức 'TransformNode' và một trong số chúng gọi' transformNodeToObject'. Nhận xét của tôi có liên quan đến việc cần thực hiện một số thao tác ** lưu ** để đảm bảo mã hóa thích hợp. Nó có thể được lưu dễ dàng ví dụ: bằng cách gọi SaveToXML và chuyển đối số var của kiểu UTF8String. – pf1957