2016-05-13 14 views
0

背景:データの一部をエクスポートするためにSQL Serverにストアドプロシージャを作成しています。ファイルはXML形式である必要がありますので、質問にfor xmlとBCPingしています。Unicode XMLとPowershellのBCPから返される文字が奇妙なUTF-8に変換される

Stringデータvarchar(ないnvarchar)であるが、いくつかの文字が正しく変換されませんでしたので、私たちは-w代わりの-CACPを使用するためにBCP文を変更しました。私たちのエンドユーザは、UTF-8を要求するファイルサイズを嫌っていました。ファイルがより正確なXMLになるように、XMLディレクティブ文を入れたいと思っていました。少しPowershellは両方の世話をするように見えました。

一般的に言うと、プロセスは私たちが望んでいることを実行していますが、内部にCR/LFを含むデータには奇妙なものがあります。つまり、BCPはCRを文字列 "$#x0D; LFを0x0Aのままにしています(まあ、Unicodeに相当し、0x00バイトもあります)。 Powershellステートメントは、 "$#x0D;"を処理するように見えます。 (Unicode)0x0Aを(UTF-8)空間に変換します。これは私たちが望むものではありません!興味深いのは、(Unicode)0x0Aが(UTF-8)CR/LFに変換されて戻ってきても、XMLディレクティブの部分を残しておけば、 "$#x0D;データにも

ここでは、私たちが行っている作業の簡略化した例を示しました。 MyDatabaseを作業用のDBに変更して、C:\のパスを変更すると、結果のファイルが表示されます。視覚的に見るためにTextPadを使用しています。実際のバイト単位の出力を調べるにはHexEditを使用します。誰も助けてくれる明白な何かを見ますか?私はなぜFORのXML/BCPは、だけでなく、LFをコードしないことを確認していない...

create table MyDatabase.dbo.TestTable (
    StringData varchar (1000) 
) 

insert into MyDatabase.dbo.TestTable (StringData) 
    select 
     'I have return characters in me.' + char (13) + char (10) + 'Will the file I''m output to be okay?' 

declare @Query varchar (2000) 
declare @Command varchar (2000) 

set @Query = 'select * ' 
      + 'from MyDatabase.dbo.TestTable with (nolock) ' 
      + 'for xml path (''StringData''), root (''TableData''), elements, type' 

set @Command = 'bcp "' + @Query + '" queryout C:\TestXMLUnicodeData_1.xml -w -T -S' + cast(@@ServerName as varchar) 

exec master.dbo.xp_cmdshell @Command 

set @Command = 'powershell "Get-Content C:\TestXMLUnicodeData_1.xml | Set-Content -Encoding UTF8 C:\TestXMLUTF8Data_1.xml' 

exec master.dbo.xp_cmdshell @Command 

set @Query = 'select * ' 
      + 'from MyDatabase.dbo.TestTable with (nolock) ' 
      + 'for xml path (''StringData''), root (''TableData''), elements, type' 

set @Command = 'bcp "' + @Query + '" queryout C:\TestXMLUnicodeData_2.xml -w -T -S' + cast(@@ServerName as varchar) 

exec master.dbo.xp_cmdshell @Command 

set @Command = 'powershell "''<?xml version=\"1.0\" encoding=\"UTF-8\"?>'' + (Get-Content C:\TestXMLUnicodeData_2.xml)' 
       + ' | Set-Content -Encoding UTF8 C:\TestXMLUTF8Data_2.xml' 

exec master.dbo.xp_cmdshell @Command 

答えて

0

を少しグーグルでてきましたが、私たちの特定の状況に関連する何かを見つけるように見えることはできませんCR。

しかし、2番目のファイルにスペースが挿入されているのは、Get-ContentとPowerShellの自動文字列配列列挙の動作のためです。

デフォルトでは、Get-Contentは一度に1行を読み込み、実際にはデータファイルの行を含む文字列の配列を返します。あなたの例では、Get-ContentはLF文字をEOLターミネータとして使用しています(EOLターミネータはデータから破棄されます)。

Get-Contentの仕組みについては、このブログ記事を参照してください。
http://powershell.org/wp/2013/10/21/why-get-content-aint-yer-friend/

powershellが文字列配列を自動的に列挙する方法のためにスペースが挿入されています。そのブログが推奨するようには、Get-contentコマンドで-RAWオプションを使用

$a = "One", "Two", "Three" 
$a 
Write-Output ("The string concatentation causes an automatic enumeration of the string array. Notice the automatic spaces inserted after data at index zero" + $a) 

は特許自動的なスペースがありませんので、ゲット・コンテンツは一つのアイテムを持つ配列を返しますので、あなたが探しているの出力を得るように思われます。

+0

ありがとうございました。残念ながら、私はそれが最も問題を引き起こしている最初のことだと思います。私は、プロセスの始めにCRとLFの両方を明示的にエンコードし、Powershellを使用してエンコードされた文字列をエンディングのCR/LFに戻す作業をさらに進めました。結局のところ、CPUサイクルはいくらですか? : - / –

関連する問題