2011-10-13 63 views
0

場景:如何不斷變化的消費XML

輸入:

  • 其結構上的外部團隊的憐憫不斷變化的XML文件。
  • 這不是一個很好的XML。
  • 元素標籤有時候會改變。

所需的輸出:

  • 其中所採用的應用程序的其他部分

問題預定類的對象:

  • 如何映射改變元件的標籤帶固定的類名。

C#語言。

enter code here 
ReadIn("input.xml"); 

public static GbtInfo ReadIn(string path) 
    { 
     using (XmlReader reader = new XmlTextReader(path)) 
     { 
      reader.ReadToDescendant("SYSTEM"); 
      return Serializers.ParseNode<GbtInfo>(reader); 
     } 
    } 

public static T ParseNode<T>(XmlReader reader) 
{ 
    Type t = typeof(T); 
    return (T)ParseNode(t, reader); 
} 

public static object ParseNode(Type type, XmlReader reader) 
{ 
    var instance = Activator.CreateInstance(type); 

    IXmlSerializable xmlSerializable = instance as IXmlSerializable; 
    if (xmlSerializable != null) 
    xmlSerializable.ReadXml(reader); 
    return instance; 
} 

public static object ParseNode(string name_space, string elementName, XmlReader reader) 
{ 
    Type t = Type.GetType(name_space + "." + elementName, false, true); 
    return ParseNode(t, reader); 
} 





public void ReadXml(System.Xml.XmlReader reader) 
    { 
     this.reader = reader; 
     string nextElement; 
     parent = reader.Name; 
     PropertyInfo propertyinfo = null; 

     //Setting a flag if the current node is empty. 
     bool isEmptyElement = reader.IsEmptyElement; 
     //Code that parses the attributes out of the Node. 
     if (reader.HasAttributes) 
     { 
      for (int i = 0; i < reader.AttributeCount; i++) 
      { 
       reader.MoveToAttribute(i); 
       nextElement = Utilities.RemoveSpecialChar(reader.Name); 
       propertyinfo = (GetType()).GetProperty(nextElement, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); 
       if (propertyinfo != null) 
        propertyinfo.SetValue(this, reader.Value, null); 
       else 
        PrintError(nextElement); 


      } 
     } 
     if (!isEmptyElement)//if the element is not empty get all the children 
     { 
      reader.Read(); 
      Utilities.SkipToContent(reader); 
      while (!(reader.Name.Equals(parent) && reader.NodeType == XmlNodeType.EndElement)) 
      { 
       reader.MoveToContent(); 
       //Case when Node Element is an object type with string 
       if (reader.NodeType == XmlNodeType.Text) 
       { 
        propertyinfo = (GetType()).GetProperty("Value", BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); 

        if (propertyinfo != null) 
         propertyinfo.SetValue(this, reader.Value, null); 
        else 
         PrintError("Value"); 

        //Testing Console.WriteLine(nextelement + " => " + reader.Value); 
        reader.Read(); 
        Utilities.SkipToContent(reader); 
       } 
       if (reader.NodeType == XmlNodeType.Element) 
       { 
        nextElement = Utilities.RemoveSpecialChar(reader.Name); 
        propertyinfo = (GetType()).GetProperty(nextElement, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); 
        if (propertyinfo != null) 
        { 
         if (propertyinfo.PropertyType.FullName.Equals("System.String")) 
         { 
          reader.Read();//read to get the text 
          if (reader.NodeType != XmlNodeType.Text) 
           throw new InvalidOperationException("Special Case encountered check XML"); 
          propertyinfo.SetValue(this, reader.Value, null); 
          //Testing Console.WriteLine(reader.Value); 
          reader.ReadToNextSibling("dummy");//this will read to the parent end tag 
          reader.Read(); 
          Utilities.SkipToContent(reader); 
         } 
         else 
         { 

          System.Collections.IList list = propertyinfo.GetValue(this, null) as System.Collections.IList; 
          if (list != null) 
          { 
           list.Add(Serializers.ParseNode(Namespace, nextElement, reader)); 

          } 
          else 
          { 
           propertyinfo.SetValue(this, Serializers.ParseNode(Namespace, nextElement, reader), null); 
          } 
         } 
        } 
        else 
        { 
         PrintError(nextElement); 
         reader.ReadToNextSibling(); 
        } 
       } 
      } 
     } 

     //move to the next element 
     reader.Read(); 
     Utilities.SkipToContent(reader); 
    } 


    // Utilities Method 

     private void PrintError(string errorElement) 
     { 
      IXmlLineInfo info = reader as IXmlLineInfo; 
      Log.LogIt("The attribute " + errorElement + " does not exist under " + parent + " Error Occurred at Line " 
         + info.LineNumber + " Col " + info.LinePosition, LogMessageType.Warning); 
      info = null; 
    } 

    public static XmlReader SkipToContent(XmlReader reader) 
     { 
      int count = 0; 
      while (reader.NodeType != XmlNodeType.Element && reader.NodeType != XmlNodeType.Attribute && 
        reader.NodeType != XmlNodeType.EndElement && reader.NodeType != XmlNodeType.Text) 
      { 
       reader.Read(); count++; 
       if (count > 2) 
       { 
        //Console.WriteLine(" Stuck"); 
        if (reader.EOF) 
        { 
         break; 
        } 
       } 
      } 
      return reader; 
     } 

/// <summary> 
/// Removes special symbols like "-","_","." from Node element name inorder to match it with the respective objects. 
/// </summary> 
/// <param name="str"></param> 
/// <returns></returns> 
public static string RemoveSpecialChar(string str) 
     { 
      str = str.Replace("-", ""); 
      str = str.Replace(".", ""); 
      str = str.Replace("_", ""); 
      return str; 
    } 
+8

聽起來像濫用XML。 – vcsjones

+6

「這不是一個很好的XML」 - 所以你問「如何理解未格式化的文本數據」?很多人在解決這個問題,至今沒有找到特別簡單和通用的解決方案:)。 –

+3

毫無疑問,您的外部團隊需要遵循規範,並且如果沒有嚴格遵循該規範,則需要將XML反饋給外部團隊進行修復。沒有人需要忍受這種公牛** t。 –

回答

2

首先,您應該強制您的外部團隊爲您提供至少一個語法正確的XML文件。這是一個組織問題,但如果你不能解決這個問題,其他一切都沒有什麼意義。

其中所採用的應用程序

使用一個如下的其它部分的預定義類的對象。在代碼中動態訪問內容,並處理運行時缺少標籤或塊時的情況。避免將元素標記映射到C#類中的靜態定義的屬性,只要您不知道元素標記在下一次迭代中不會再發生變化。如果您的代碼依賴於某些特定的元素標記,則將其定義爲字符串常量一次在代碼的中心位置,以便在外部團隊重新命名標記時輕鬆更改它們。