Problem parsing an XML file

I have the following XML file:

<?xml version="1.0" encoding="utf-8" ?> <strategies> <strategy name="God Class"> <gate type="AND"> <rule> <metric>LOC</metric> <comparison>greater than</comparison> <value>850</value> </rule> <rule> <metric>FANIN</metric> <comparison>greater than</comparison> <value>850</value> </rule> <rule> <metric>FANOUT</metric> <comparison>greater than</comparison> <value>850</value> </rule> </gate> </strategy> <strategy name="TClass"> <gate type="OR"> <gate type="AND"> <rule> <metric>LOC</metric> <comparison>greater than</comparison> <value>100</value> </rule> <rule> <metric>NOM</metric> <comparison>greater than</comparison> <value>200</value> </rule> </gate> <rule> <metric>NOPAR</metric> <comparison>greater than</comparison> <value>300</value> </rule> </gate> </strategy> </strategies> 

Now I am trying to parse this document and extract the rules. The first strategy is simple with the following code:

 public static void parseRules() { XDocument document = XDocument.Load(FILE); XElement root = document.Root; foreach (XElement elem in root.Elements()) { String name = elem.Attribute(STRATEGY_NAME).Value; XElement gate = elem.Element(GATE_NAME); List<Rule> rules = new List<Rule>(); foreach (XElement r in gate.Elements()) { String metric = r.Element(METRIC_NAME).Value; String comparisation = r.Element(COMPARISON_NAME).Value; int threshold = Convert.ToInt32(r.Element(VALUE_NAME).Value); Rule rule = null; if (comparisation.Equals(GREATER_THAN_NAME)) { rule = new Rule(metric, Rule.GREATHER_THAN, threshold); } else if (comparisation.Equals(SMALLER_THAN_NAME)) { rule = new Rule(metric, Rule.SMALLER_THAN, threshold); } rules.Add(rule); } ISpecification spec = rules.ElementAt(0); if (gate.Attribute(TYPE_NAME).Value.Equals(AND)) { for (int i = 1; i < rules.Count; i++) { spec = spec.And(rules.ElementAt(i)); } } else if (gate.Attribute(TYPE_NAME).Value.Equals(OR)) { for (int i = 1; i < rules.Count; i++) { spec = spec.Or(rules.ElementAt(i)); } } DetectionStrategy strategy = new DetectionStrategy(spec, name); } } } 

Obviously, this only works for XML files that have only rules in one gate, and not other gates, as in the second example. However, I cannot make out the enclosed gate. Any clues where to start?

+4
source share
4 answers

Using XDocument or XmlDocument for XML parsing will be very fragile.

I suggest you create an object model that will serve this structure and logic, and use XML serialization / deserialization to save or hydrate.

At the end of the day, this XML representation is just one possible representation of your logic, you can use them as JSON, Binary, ...

Example:

 public class Strategy { [XmlAttribute] public string Name {get; set;} [XmlElement("Gate")] public Gate MainGate {get; get} } /// ........... public class Gate { XmlElement("Gate") public Gate ChildGate {get; set;} // ... } 

UPDATE

This is how you serialize (easy-peasy)

 XmlSerializer xs = new XmlSerializer(typeof(Strategy)); FileStream fs = new FileStream("strategy.xml", FileMode.Create); xs.Serialize(fs, myStrategy); 
+4
source

I would create a strategy object containing a list of strategy objects. The strategy object will contain the Gate object, etc., and then serialize the XML into an instance of these objects. You may run into problems with serializing this xml, as it is not uniform. You will need to include the Gates element as a child of the Gate, so that you can include your list of Gate objects ...

An example without a nested gate ...

 <Gate> <Gates> </Gates> ... </Gate> 

Example with a nested gate ...

 <Gate> <Gates> <Gate> <Gates> </Gates> ... </Gate> </Gates> ... </Gate> 
+1
source

This problem is best resolved with SAX. There are some SAX implementations in .NET, although I want .NET to have a built-in implementation.

The problem is that you only have two cycles, most of which you can go down two levels. It can be tedious to add extra loops. There is a better model.

If you should not use SAX, you need to create a universal engine that can handle any number of gates inside the gate.

It will be something like this

  public void parseRules (State state, IEnumerable<Element> elements) { foreach (Element element in elements) { if (element.Name.Equals("strategy")) { parseNewStrategy(state, element); } else if (element.Name.Equals("gate")) { parseNewGate(state,element); } } } 

I greatly simplify this. If you want to design this correctly, use the Visitor template. This is what the SAX engine would do. This will allow you to β€œvisit” each element of the document and take certain predefined actions whenever you reach the element.

Something like that

If I get to the strategy, save his name and put a status field that says that I'm in the strategy. As soon as I got into the gate data warehouse, but I do not create an array of rules yet. If I hit a new shutter, then this new operation will be pushed onto the stack. If I hit a rule, create a new array of rules and associate it with the top most gates.

+1
source

If you can access the XML definition of the XSD file, you can use the xsd.exe utility that comes with Visual Studio to automatically create a C # class to process the XML file. Using the resulting C # code, you can load XML into a memory structure, which is easily accessible as a set of elements with properties that you can consider like any other collection.

This method also provides a convenient way to write data to a file using the generated class.

+1
source

Source: https://habr.com/ru/post/1333903/


All Articles