2013-04-18 73 views
5

在Delphi XE2中,我正在對接收到的XML文件進行xslt轉換,以刪除所有名稱空間信息。
問題:它改變阻止將utf-8 XML轉換爲utf-16的XSLT轉換?

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

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

這是我找回從Exchange服務器的XML:

<?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> 

這是消除命名空間信息的功能:

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 } 

但在此之後,它突然一個UTF-16號文件:

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

谷歌搜索 「XSL UTF-8 UTF-16」 之後,我嘗試了幾件事情:

  • 更改線路(例如Output DataTable XML in UTF8 rather than UTF16

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

    到兩種:

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

    這沒有奏效。
    (這將是最佳的解決方案,根據http://www.xml.com/pub/a/2002/09/04/xslt.html「的編碼屬性實際上不僅僅添加編碼聲明的結果文檔;它告訴XSLT處理器使用該編碼寫出來的結果。」)

  • 更改線路(如XslCompiledTransform uses UTF-16 encoding

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

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

    留下了開始的XML標籤,但如果我那麼就PR epend

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

    我將失去字符,因爲沒有實際的utf轉換完成。

  • IXMLDOMdocument2不具有Encoding財產

任何想法如何解決這一問題?

備註/背景:

  • 如果一切都失敗也許仍然有對UTF-16的XML數據更改爲UTF-8的選項,但是這是一個完全不同的方法。

  • 我想要做的一切utf-8,因爲我通過EWS與Exchange服務器通信,並將http請求標頭設置爲utf-16不起作用:Exchange告訴我,內容類型的文本/ XML; charset = utf-16'不是預期的類型'text/xml; charset = utf-8'。EWS返回utf-8(請參閱開始發佈)。

+2

@Gserg感謝格式編輯,我正在與代碼塊在項目符號點摔跤。 –

回答

1

要在你原來的代碼使用IXMLDocument,它應該是這樣的:

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 

現在變量UTF8應該包含轉換XML的UTF-8編碼,如果你想保存到流/文件,替換SaveToXML通過

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

的問題是使用transformNode方法,它返回一個字符串,並用MSXML這樣的字符串是UTF-16編碼。因此,您需要爲結果創建一個空的MSXML DOM文檔,並使用the transformNodeToObject method,傳遞空DOM文檔作爲第二個參數,然後可以將結果文檔保存到文件或流中,編碼應符合xsl:output指令中的規定。

+0

我想說,DOM是內部使用UTF-16實現的,因此目標DOM文檔中的轉換結果也將以UTF-16編碼。編碼本身應該是輸入/輸出過濾器的一項任務,所以我期望有必要調用例如'iXMLDocument.SaveToXML(AUTF8String)' – pf1957

+0

MSXML沒有名爲'SaveToXML'的方法。它在DOM文檔上有一個名爲'save'的方法,我的建議是在創建空的DOM文檔上使用該方法,然後傳遞給'transformNodeToObject'方法。這樣,如果您保存到文件或流中,則編碼應該符合預期。這是不可能的,如果你使用'transformNode'。 –

+0

我知道。我過去不直接調用MSXML,而是通過「IXMLDocument」/「IXMLNode」。有重載的方法'TransformNode',其中一個調用'transformNodeToObject'。我的評論一直關注執行某種** save **操作以確保正確編碼的必要性。它可以很容易地保存,例如通過調用SaveToXML並傳遞類型爲UTF8String的var參數。 – pf1957