XML 圧縮ユニットテストコード - クラスプログラム {
- パブリック静的文字列XML = @" <? xml バージョン="" 1.0 ""エンコーディング="" utf -16"" ?>
- <お客様>
- <顧客ID > ALFKI </顧客ID >
- < PO > 9572658 </ PO >
- <住所 アドレスタイプ= ""仕事 "" >
- <通り>メインストリート 1 番地</通り>
- <都市>どこでも</都市>
- <州> NJ </州>
- <郵便番号> 08080 </郵便番号>
- </住所>
- <注文>
- <注文ID > 10966 </注文ID >
- <行項目>
- <製品ID > 37 </製品ID >
- <単価> 26.50 </単価>
- <数量> 8 </数量>
- <説明>グラバッド ラックス</説明>
- </行項目>
- <行項目>
- <製品ID > 56 </製品ID >
- <単価> 38.00 </単価>
- <数量> 12 </数量>
- <説明>アリスおばあちゃんのニョッキ</説明>
- </行項目>
- </注文>
- </顧客> ";
- 静的void Main(文字列[]引数) {
- XmlZip zip =新しいXmlZip();
-
- byte[] bs = Encoding.UTF8.GetBytes (XML);
- Console.WriteLine("元のファイルの長さ: {0}", bs.Length);
- メモリストリームms =新しいメモリストリーム();
- DeflateStream圧縮された zipStream = new DeflateStream(ms, CompressionMode.Compress, true);
- 圧縮されたzipStream.Write(bs, 0, bs.Length);
- 圧縮されたzipStream.Close();
- Console.WriteLine("Deflate 圧縮された長さ: {0}", ms.Length);
-
- zip.Init(XML);
- bs = zip.XmlToBytes (XML);
- Console.WriteLine("XML 圧縮長: {0}", bs.Length);
- 文字列str = zip.BytesToXml (bs);
- Console.WriteLine("復元された長さ: {0}", Encoding.UTF8.GetByteCount(str));
- Console.WriteLine(str);
-
-
- ms =新しいMemoryStream();
- 圧縮された zipStreamを新しいDeflateStream(ms, CompressionMode.Compress, true);
- 圧縮されたzipStream.Write(bs, 0, bs.Length);
- 圧縮されたzipStream.Close();
- Console.WriteLine("最初に XML 圧縮を行い、次に Deflate 圧縮後の長さ: {0}", ms.Length);
- コンソールのキーを読み取ります。
-
- }
- }
テスト出力 元のファイルの長さ: 740 圧縮後の長さ: 438 XML圧縮長: 295 修復後の長さ: 727 - <? xml バージョン= "1.0" エンコーディング= "utf-16" ?>
- <お客様>
- <顧客ID > ALFKI </顧客ID >
- < PO > 9572658 </ PO >
- <住所 住所タイプ= "仕事" >
- <通り>メインストリート 1 番地</通り>
- <都市>どこでも</都市>
- <州> NJ </州>
- <郵便番号> 08080 </郵便番号>
- </住所>
- <注文>
- <注文ID > 10966 </注文ID >
- <行項目>
- <製品ID > 37 </製品ID >
- <単価> 26.50 </単価>
- <数量> 8 </数量>
- <説明>グラバッド ラックス</説明>
- </行項目>
- <行項目>
- <製品ID > 56 </製品ID >
- <単価> 38.00 </単価>
- <数量> 12 </数量>
- <説明>アリスおばあちゃんのニョッキ</説明>
- </LineItem>
- </注文>
- </顧客>
XML 圧縮および Deflate 圧縮後の長さ: 357 XML 圧縮後のデータは、元のデータの約 3 分の 1 であることがわかります。圧縮率は他の独自の圧縮アルゴリズムほど高くないかもしれませんが、効果は満足のいくものです。さらに、私のアルゴリズムは比較的汎用的です。通信相手が XML スキーマを知っていれば、または完全なサンプル コードさえあれば、圧縮された通信を実行できます。私は機能テストのみを行っており、パフォーマンス テストは行っていません。まずは私のアイデアを参考にしてください。 完全なコード 一般的な原則は、通信する双方が XML 文書のノード名と属性名の辞書を保持し、送信側は送信時に ushort を使用して元の XML タグと属性名を置き換えます。受信側は辞書を介して ushort を元の要素名と属性名に変換し、不要な重複タグを大量に排除します。 このコードはこの記事で例としてのみ使用されています。コードはカジュアルに書かれており、防御力や堅牢性はありません。 - 内部列挙型 ItemType {
- 要素、
- アトリチューブ
- }
- 内部クラス XmlNodeItem {
- パブリック文字列 Xpath { 取得; 設定; }
- パブリック文字列テキスト { 取得; 設定; }
- パブリック ItemType アイテムタイプ { 取得; 設定; }
- パブリックオーバーライド文字列ToString() {
- Xpath を返します。
- }
- }
- 内部クラス MyXpath {
- リンクリスト<文字列> _node =新しいLinkedList <文字列> ();
- パブリック void AddElement(文字列名) {
- _node.AddLast(文字列.Format("/{0}", 名前));
- }
- パブリック void AddAttribute(文字列名) {
- _node.AddLast(文字列.Format("/@{0}", 名前));
- }
- パブリック void RemoveLastElement() {
- _node.RemoveLast();
- }
- パブリックオーバーライド文字列ToString() {
- StringBuilder sb =新しいStringBuilder();
- LinkedListNode <文字列> ノード= _node.First ;
- sb.Append(ノード.Value);
- while ((ノードnode = node.Next) != null) {
- sb.Append(ノード.Value);
- }
- sb.ToString() を返します。
- }
- }
- クラスXmlZip {
- 辞書< ushort 、 XmlNodeItem > _map =新しい辞書< ushort 、XmlNodeItem > ();
- 辞書<文字列、ushort > _map2 =新しい辞書<文字列、 ushort > ();
- MyXpath _path =新しいMyXpath();
-
- パブリック void Init(文字列 xmlInput) {
- StringReader sr =新しいStringReader(xmlInput);
- XmlReaderリーダー= XmlReader.Create (sr);
- メモリストリームms =新しいメモリストリーム();
- ショートi = 1 ;
- (reader.Read()) の間 {
- スイッチ (リーダー.NodeType) {
- XmlNodeType.Elementの場合:
- _path.AddElement(リーダー.Name);
- _map[i++] = 新しいXmlNodeItem() {
- Xpath = _path.ToString ()、
- テキスト= reader.Name 、
- アイテムタイプアイテムタイプ= アイテムタイプ.Element
- };
- (リーダー.HasAttributes)の場合{
- リーダー.MoveToFirstAttribute();
- _path.AddAttribute(リーダー.Name);
- _map[i++] = 新しいXmlNodeItem() {
- Xpath = _path.ToString ()、
- テキスト= reader.Name 、
- アイテムタイプアイテムタイプ= アイテムタイプ.属性
- };
- _path.最後の要素を削除します。
- (reader.MoveToNextAttribute()) の間 {
- _path.AddAttribute(リーダー.Name);
- _map[i++] = 新しいXmlNodeItem() {
- Xpath = _path.ToString ()、
- テキスト= reader.Name 、
- アイテムタイプアイテムタイプ= アイテムタイプ.属性
- };
- _path.最後の要素を削除します。
- }
- リーダー.MoveToElement();
- }
- reader.IsEmptyElement の場合、_path.RemoveLastElement();
- 壊す;
- XmlNodeType.EndElementの場合:
- _path.最後の要素を削除します。
- 壊す;
- デフォルト:
- 壊す;
- }
- }
- foreach (KeyValuePair < ushort 、 XmlNodeItem >ペア in _map) {
- _map2[pair.Value.Xpath] = ペア.Key;
- }
- }
-
- パブリック byte[] XmlToBytes(文字列 xmlInput) {
- StringReader sr =新しいStringReader(xmlInput);
- XmlReaderリーダー= XmlReader.Create (sr);
- メモリストリームms =新しいメモリストリーム();
- BinaryWriter bw =新しいBinaryWriter(ms);
- (reader.Read()) の間 {
- ushort インデックス;
- バイト[] bs;
- スイッチ (リーダー.NodeType) {
- XmlNodeType.Elementの場合:
- _path.AddElement(リーダー.Name);
- if (_map2.TryGetValue(_path.ToString(), 出力インデックス)) {
- bw.Write(インデックス);
- }
- (リーダー.HasAttributes)の場合{
- リーダー.MoveToFirstAttribute();
- _path.AddAttribute(リーダー.Name);
- if (_map2.TryGetValue(_path.ToString(), 出力インデックス)) {
- _path.最後の要素を削除します。
- bw.Write(インデックス);
- bs = Encoding.UTF8.GetBytes (リーダー.Value);
- bw.Write((ushort)bs.Length);
- bw.Write(bs);
- }
- (reader.MoveToNextAttribute()) の間 {
- _path.AddAttribute(リーダー.Name);
- if (_map2.TryGetValue(_path.ToString(), 出力インデックス)) {
- _path.最後の要素を削除します。
- bw.Write(インデックス);
- bs = Encoding.UTF8.GetBytes (リーダー.Value);
- bw.Write((ushort)bs.Length);
- bw.Write(bs);
- }
- }
- リーダー.MoveToElement();
- }
- (リーダーが空の要素である場合){
- _path.最後の要素を削除します。
- bw.Write(ushort.MaxValue);
- }
- 壊す;
- XmlNodeType.EndElementの場合:
- _path.最後の要素を削除します。
- bw.Write(ushort.MaxValue);
- 壊す;
- XmlNodeType.Textの場合:
- bw.Write((ushort)0);
- bs = Encoding.UTF8.GetBytes (リーダー.Value);
- bw.Write((ushort)bs.Length);
- bw.Write(bs);
- 壊す;
- デフォルト:
- 壊す;
- }
- }
- bw.Close();
- ms.Close();
- リーダー.Close();
- ms.ToArray() を返します。
- }
-
- パブリック文字列BytesToXml(byte[] bytes) {
- メモリストリームms =新しいメモリストリーム(バイト);
- BinaryReader br =新しいBinaryReader(ms);
- StringBuilder sb =新しいStringBuilder();
- StringWriter sw =新しいStringWriter(sb);
- XmlWriterSettings設定=新しいXmlWriterSettings();
- 設定.インデント= true ;
- XmlWriterライター= XmlWriter .Create(sw, settings);
-
- XmlNodeItem 項目;
- (br.PeekChar() != -1) の間 {
- ushort readFlag = br .ReadUInt16();
- 長さ;
- バイト[] bs;
- 文字列 str;
- if (_map.TryGetValue(readFlag, out item)) {
- if ( item.ItemType == ItemType.Element)
- writer.WriteStartElement(item.Text);
- そうでない場合 ( item.ItemType == ItemType.Attritube) {
- len = br.ReadUInt16 ();
- bs = br.ReadBytes (len);
- str = Encoding.UTF8.GetString (bs);
- writer.WriteAttributeString(item.Text, str);
- }
- }
- そうでない場合( readFlag == 0){
- len = br.ReadUInt16 ();
- bs = br.ReadBytes (len);
- str = Encoding.UTF8.GetString (bs);
- ライター.WriteString(str);
- }
- そうでない場合 ( readFlag == ushort.MaxValue) {
- ライター.WriteEndElement();
- }
- }
- ライターをフラッシュします。
- ライター.Close();
- sw.Close();
- br.閉じる();
- sb.ToString() を返します。
- }
- }
|