C〓〓を使ってアンチプログレッシブplistファイルを並べます.

26298 ワード

私たちのプロジェクトはクロスプラットフォームで、最初に作ったのはios版ですので、包装のxmlは全部plist形式です.plistはxcodeで逆の順に並べられやすいですが、PC版では最初に異なるファイルの構造に従って、異なる解析をしています.コードの多重性は低いです.
このプロジェクトを引き継いでから、ファイルの解析をもう一つ追加させていただきました.前のコードはちょっと乱れていると感じました.自分で直接plistファイルのアンチプログレッシブアルゴリズムを書いて、ここで皆さんと分かち合います.
 
私の考えはこのようにして、まずplistファイルの中の元素を木の形式で保存して、更に木を標準のXMLファイルに組織して、C〓〓〓〓Serializerを利用してそれを逆順に並べます.
plistファイルを解析するには、まずそのファイルのフォーマットを確認します.以下はplistファイルです.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>zh_CN</string>
	<key>CFBundleDisplayName</key>
	<string>${PRODUCT_NAME}</string>
	<key>CFBundleExecutable</key>
	<string>${EXECUTABLE_NAME}</string>
	<key>CFBundleIconFiles</key>
	<array>
		<string>Icon.png</string>
		<string>[email protected]</string>
	</array>
	<key>CFBundleIcons</key>
	<dict>
		<key>CFBundlePrimaryIcon</key>
		<dict>
			<key>CFBundleIconFiles</key>
			<array>
				<string>Icon.png</string>
				<string>[email protected]</string>
			</array>
			<key>UIPrerenderedIcon</key>
			<false/>
		</dict>
	</dict>
	<key>CFBundleIdentifier</key>
	<string>com.qixiangWeather.${PRODUCT_NAME:rfc1034identifier}</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>${PRODUCT_NAME}</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>1.0</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>UIRequiredDeviceCapabilities</key>
	<array>
		<string>armv7</string>
	</array>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
	</array>
</dict>
</plist>
標準のxmlファイルとは多くの違いがあることが分かります.次のようないくつかのラベルフォーマットを持っていて、異なるタイプのデータを表しています.
Core Fundation         XML
CFsting                   <ストリングス
CFNumber              
CFDate                     <ダテ
CFBoolean             
CFDaa                     CFArray                   
CFDictionry           CFDicationryでは、主にキーペアからなります.したがって、XMLでは、CFDICメンバーのキーは<key>に対応しています.その後はその値になります.
この特徴からキーの種類を挙げることができます.
enum EnumValueType
{
    DICT,
    ARRAY,
    NUMBER,
    STRING,
    DTAE,
    BOOLEAN,
    DATA,
}
今私達はplistフォーマットを木に変えて、データ構造を定義します.
 class DataType
    {
        public int ID { get; set; }//  ID
        public string DataName { get; set; }//      
        public EnumValueType ValueType { get; set; }//     
        public string Value { get; set; }//   
        public int parentID { get; set; }//     ID
        public List<int> childrenID { get; set; }//     
    }
解析のアルゴリズムは再帰的なプロセスです.ここでリストを使ってツリーを保存します.なぜlistの中のIDが連続していないのかと疑問に思ったら、遍歴の過程は前の順序であると教えてくれます.
class ReadPlist
    {
        public List<DataType> DateList { get; set; }
        int saveid = 1;
        DataType RootNode;
        int count;
        int itemCount;
        
        public ReadPlist()
        {
            count = 1;
            itemCount = 0;
            RootNode = new DataType();
            RootNode.ID = count;
            RootNode.DataName = null;
            RootNode.parentID = 0;
            RootNode.ValueType = EnumValueType.DICT;
            RootNode.childrenID = new List<int>();
            this.DateList = new List<DataType>();
            DateList.Add(RootNode);
            
        }
 public XDocument LoadFromFile(string path)
        {
            return XDocument.Load(path);
        }
        public void XMLparser(string path)
        {
            XDocument doc = LoadFromFile(path);
            XElement FirstElement = doc.Root.Element("dict");
            DateList[0].childrenID = XMLOnce(FirstElement, 1);
            foreach (var item in DateList)
            {
                if (item.Value == "FALSE"||item.Value == "TRUE")
                {
                    item.Value = item.Value.ToLower();
                }
                try
                {
                    if (Char.IsNumber(item.DataName[0]))
                    {
                        item.DataName.Insert(0, "_");
                    }
                }
                catch (System.Exception ex)
                {
                    
                }
                
            }
            print();
        }

        public List<int> XMLOnce(XElement nowElement,int parentid)
        {
            List<DataType> DataTemp = new List<DataType>();
            List<int> IDList = new List<int>();
            List<int> childrenIDList = new List<int>();
            var keys = from k in nowElement.Elements("key")
                      select k;
            var values = from v in nowElement.Elements()
                         where v.Name != "key"
                         select v ;
            for (int i = 0; i < values.ToList().Count; i++)
            {
                int id = ++count;
                EnumValueType valuetype = (EnumValueType)Enum.Parse(typeof(EnumValueType), values.ToList()[i].Name.LocalName.ToString().ToUpper(), true);
                string value = null;
                if (valuetype == EnumValueType.ARRAY)
                {
                    XElement newElement = nowElement.Elements().Except(nowElement.Elements("key")).ElementAt(i);
                    int num = newElement.Elements().Count();
                    for (int j = 0; j < num;j++ )
                    {
                        newElement.AddFirst(new XElement("key", "item"));
                    }
                    childrenIDList = XMLOnce(newElement,id);
                }
                else if (valuetype == EnumValueType.DICT)
                {
                    XElement newElement = nowElement.Elements().Except(nowElement.Elements("key")).ElementAt(i);
                    childrenIDList = XMLOnce(newElement, id);
                }
                else
                {
                    value = values.ToList()[i].Value.ToString();
                }
                
                try
                {
                    DataTemp.Add(new DataType()
                    {
                        DataName = keys.ToList()[i].Value.ToString(),
                        ValueType = valuetype,
                        ID = id,
                        Value = value,
                        parentID = parentid,
                        childrenID = childrenIDList
                    });
                }
                catch (System.Exception ex)
                {
                    DataTemp.Add(new DataType()
                    {
                        DataName = "itemContent",
                        ValueType = valuetype,
                        ID = id,
                        Value = value,
                        parentID = parentid,
                        childrenID = childrenIDList
                    });
                }

            }
            foreach (var item in DataTemp)
            {
                IDList.Add(item.ID);
            }
            DateList.AddRange(DataTemp);
            return IDList;
        }
}
はい、次のステップはこの木を標準のxml形式にします.ここでxmlに対する解析はlinq to xmlです.linqに慣れていない友達がいれば、庭の中の他の文章を見て勉強してもいいです.
 class ConvertXML
    {
        List<DataType> DataList{get;set;}

        public ConvertXML (List<DataType> datalist)
        {
            DataList = datalist;
        }
        
        public XDocument xdoc = new XDocument(new XDocument(new XDeclaration("1.0", "utf-8", "yes"), new XElement("Model")));
        public XDocument creatXML()
        {
            xdoc.Element("Model").SetAttributeValue("id","1");
            foreach (var item in DataList)
            {
                if (DataList[0].childrenID.Contains(item.ID))
                {
                    //xdoc.Element("Model").Add(new XElement(item.DataName, item.Value));
                    XElement newElement = xdoc.Descendants().Where(e => e.Attribute("id").Value == "1").First();
                    newElement.Add(new XElement(item.DataName, item.Value, new XAttribute("id", item.ID)));
                    if (item.ValueType == EnumValueType.ARRAY||item.ValueType == EnumValueType.DICT)
                    {
                        //XElement newElement = xdoc.Element("Model").Element(item.DataName);
                        creatOnce(newElement, item);
                    }
                    
                }
            }
            return xdoc;
        }

        public void creatOnce(XElement doc,DataType parent)
        {
            foreach (var item in DataList)
            {
                if (parent.childrenID.Contains(item.ID))
                {
                    string parentID = parent.ID.ToString();
                    XElement newElement = doc.Descendants().Where(e => e.Attribute("id").Value.Equals(parentID)).First();
                    newElement.Add(new XElement(item.DataName, item.Value, new XAttribute("id", item.ID)));
                    if (item.ValueType == EnumValueType.ARRAY||item.ValueType == EnumValueType.DICT)
                    {
                        //nowElement = nowElement.Element(item.DataName);
                        creatOnce(newElement,item);
                    }
                }
            }
        }

    }
残りの最後のステップは、現在の標準のxmlに対して逆順序化されました.外部にはファイルの経路と種類のプログラム名しか残していません.
class PlistSerializer : XmlSerializer 
    {
        public object Deserialize(string path,string assemblyName)
        {
            MemoryStream stream = new MemoryStream();
            ReadPlist rp = new ReadPlist();
            rp.XMLparser(path);
            ConvertXML cx = new ConvertXML(rp.DateList);
            //Console.WriteLine(cx.creatXML());
            XDocument doc = cx.creatXML();
            doc.Save(stream);
            stream.Seek(0, SeekOrigin.Begin);
            Type modelType = Type.GetType(assemblyName);
            XmlSerializer serializer = new XmlSerializer(modelType);

            try
            {
                object sender = serializer.Deserialize(stream);
                stream.Close();
                return sender;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                stream.Close();
                return null;
            }

        }
        

    }
このようにC〓〓〓を使ってplistファイルの反序化に成功して、コードは比較的に簡単で、みんなはまた必要に応じて、序文化の機能をプラスすることができます.
本コードのcodeplex:https://plistparser.codeplex.com/SourceControl/changeset/view/901458f7e974
もし皆さんがplistのプログレッシブとアンチプログレッシブの需要があるなら、私のコードは最適化や機能が足りないと思います.ネット上の第三者倉庫を利用して機能を実現することもできます.例えば、iphone-plist-netです.
 
剣を傾けて血を飛ぶブログを読んでくれてありがとうございます.
この記事のアドレス:http://www.cnblogs.com/jacklandrin/archive/2013/02/07/2908968.html
この文章の著作権は作者の所有になります.転載を歓迎して、演繹して、あるいは商業目的に用いて、しかし必ず本文の出所(リンクを含みます)を説明しなければなりません.