2014-09-30 3 views
1

XML 문서는 :XML/SGML 엔터티가있는 UTF-16을 ASCII/ANSI로 변환하는 방법은 무엇입니까?

<?xml version="1.0" encoding="utf-8"?> 
<response> 
<center> 
<b>Need to decode this -> </b> 
</center> 
</response> 

내 현재 코드 :

procedure TForm1.Button1Click(Sender: TObject); 
var 
    Doc: IXMLDocument; 
    S: AnsiString; 
    SW: WideString; 
    I: Integer; 
begin 
    Doc := TXMLDocument.Create(nil); 
    Doc.LoadFromFile('example.xml'); 
    SW := Doc.DocumentElement.ChildNodes['center'].ChildNodes['b'].NodeValue; 
    S := ''; 
    for I := 1 to Length(SW) do 
    if Ord(SW[I]) > $04FF then 
     S := S + IntToHex(Ord(SW[I]), 4) + ' ' 
    else 
     S := S + SW[I]; 
    Memo1.Text := s; 
end; 

SW가 UTF-16 (WideString으로)로 인코딩 및 문자 시퀀스 #$D83D#$DE09 포함되어 있지만 나는 XML/SGML 엔티티로 필요 '&#128521;'입니다. 어떻게 이것을 인코딩합니까?

사용되는 문자는 이것이다 :

+1

아니, 여기 델파이 7이없는 명확한. 기본적으로 XML DOM 구현이 기본 다국어 평면 외부의 문자를 디코딩하고 두 개의 UTF-16 단위로 인코딩 한 것에 만족하지 않으십니까? 그리고 다시 SGML 문자 엔티티로 인코딩하려고합니까? –

+0

정말 이해가 안되는데 XML 문서를 추가하는 것을 잊어 버렸습니다 ... 지금 추가하겠습니다 – user3802199

+0

XML 문서가 추가되었습니다 – user3802199

답변

0

http://www.fileformat.info/info/unicode/char/1f609/index.htm 수동 UTF-16 서로 게이트 쌍을 처리 (또는 타사 라이브러리를 사용) 할 필요가 ANSI 델파이를 사용하는 경우.

이 ANSI 싶게 유니 코드 델파이에서 작동합니다 :

uses 
    {$IFDEF UNICODE} 
    Xml.XMLDoc, Xml.XMLIntf, System.AnsiStrings, System.Character; 
    {$ELSE} 
    XMLDoc, XMLIntf; 
    {$ENDIF} 

{$R *.dfm} 

type 
{$IFDEF UNICODE} 
    ValueString = UnicodeString; 
{$ELSE} 
    ValueString = WideString; 
{$ENDIF} 

procedure Check(ATrue: Boolean; const AMessage: string); 
begin 
    if not ATrue then 
    raise Exception.Create(AMessage); 
end; 

function IsHighSurrogate(AChar: WideChar): Boolean; 
begin 
{$IFDEF UNICODE} 
    Result := TCharacter.IsHighSurrogate(AChar); 
{$ELSE} 
    Result := (AChar >= #$D800) and (AChar <= #$DBFF); 
{$ENDIF} 
end; 

function ConvertToUtf32(AHigh, ALow: WideChar): Integer; 
begin 
    {$IFDEF UNICODE} 
    Result := Ord(TCharacter.ConvertToUtf32(AHigh, ALow)); 
    {$ELSE} 
    Check(AHigh >= #$D800, 'Invalid high surrogate code point'); 
    Check(AHigh <= #$DBFF, 'Invalid high surrogate code point'); 
    Check(ALow >= #$DC00, 'Invalid low surrogate code point'); 
    Check(ALow <= #$DFFF, 'Invalid low surrogate code point'); 
    // This will return the ordinal value of the Unicode character represented by the two surrogate code points 
    Result := $010000 + ((Ord(AHigh) - $D800) shl 10) or (Ord(ALow) - $DC00); 
    {$ENDIF} 
end; 

function MakeEntity(AValue: Integer): AnsiString; 
begin 
    Result := Format(AnsiString('&#%d;'), [AValue]); 
end; 

function UnicodeToAsciiWithEntities(const AInput: ValueString): AnsiString; 
var 
    C: WideChar; 
    I: Integer; 
begin 
    Result := ''; 
    I := 1; 
    while I <= Length(AInput) do 
    begin 
    C := AInput[I]; 
    if C < #$0080 then 
     Result := Result + AnsiChar(C) 
    else 
    if IsHighSurrogate(C) then 
    begin 
     Check((I + 1) <= Length(AInput), 'String truncated after high surrogate'); 
     Result := Result + MakeEntity(ConvertToUtf32(C, AInput[I + 1])); 
     // Skip low surrogate 
     Inc(I); 
    end 
    else 
     Result := Result + MakeEntity(Ord(C)); 
    Inc(I); 
    end; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    Memo1.Lines.Text := string(UnicodeToAsciiWithEntities(LoadXMLDocument(
    'example.xml').DocumentElement.ChildNodes['center'].ChildNodes['b'].NodeValue 
)); 
end; 

내가 그렇게 약간이 필요할 수 있습니다 조정, 코드가 XE2에서 작동 정말 2007 년

+0

XML 문서는 UTF-8이되도록 인코딩을 선언합니다 –

+0

전체 XML 컨텐트를'UCS4String'으로 변환하고 메모리를 2-4 배로 낭비하지 않고'UnicodeString'으로 남겨두고 대신 surrogate를 찾고 변환합니다 필요할 때 엔티티에 전달합니다. 'IsSurrogatePair()'와'ConvertToUtf32()'와 같은'System.Character' 함수를보십시오. –

+0

@DavidHeffernan XML 파서가이를 내부 델파이 표현 (Delphi 7의 WideString)으로 변환하기 때문에 상관 없습니다. 그렇지 않습니까? –