XML을

2011-10-13 4 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 사양을 정확히 따르지 않으면 XML을 외부 팀에 보내 수리해야합니다. 아무도 이런 종류의 황소를 참 아야하지 않습니다. –

답변

2

먼저 구문 팀에 올바른 XML 파일을 제공해야합니다. 이것은 조직적인 문제이지만,이 문제를 해결할 수 없다면 다른 모든 것은별로 의미가 없습니다.

응용 프로그램

XmlDocument를 사용의 다른 부분에서 사용하는 미리 정의 된 클래스의 개체입니다. 코드에서 동적으로 내용에 액세스하고 런타임에 누락 된 태그 나 블록이있는 상황을 처리하십시오. 다음 반복에서 요소 태그가 더 이상 변경되지 않는다는 것을 모르는 한 C# 클래스의 정적으로 정의 된 특성에 요소 태그를 매핑하지 마십시오. 코드가 일부 특정 요소 태그를 사용하는 경우 코드의 중앙 위치에서 문자열 상수로 한 번 정의하면 외부 팀에서 태그의 이름을 쉽게 바꿀 때마다 쉽게 변경할 수 있습니다.

관련 문제