Проблема в разборе файла XML - PullRequest
4 голосов
/ 31 декабря 2010

У меня есть следующий XML-файл:

<?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>

Теперь я пытаюсь разобрать этот документ и извлечь правила. Первая стратегия проста с помощью следующего кода:

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);
            }
        }
    }

Очевидно, что это работает только для файлов XML, которые имеют только правила в одном шлюзе, а не в другом, как во втором примере. Однако я не могу разобрать вложенные ворота. Любые советы, с чего начать?

Ответы [ 4 ]

4 голосов
/ 31 декабря 2010

Использование XDocument или XmlDocument для анализа XML будет очень хрупким.

Я предлагаю вам разработать объектную модель, которая будет обслуживать эту структуру и логику, и использовать XML-сериализацию / десериализацию для сохранения или гидратации.

В конце концов, это представление XML является лишь одним из возможных представлений вашей логики, вы можете иметь их как JSON, Binary, ...

Пример:

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

Вот как вы сериализуете (легко-peasy)

XmlSerializer xs = new XmlSerializer(typeof(Strategy));
FileStream fs = new FileStream("strategy.xml", FileMode.Create);
xs.Serialize(fs, myStrategy);
1 голос
/ 31 декабря 2010

Если вы можете получить доступ к определению XSD XML-файла, вы можете использовать утилиту xsd.exe , поставляемую с Visual Studio, для автоматического создания класса C # для обработки XML-файла. Получив код C #, вы сможете загружать de XML в структуру памяти, легко доступную в виде набора элементов со свойствами, которые вы можете рассматривать как любую другую коллекцию.

Этот метод также предоставляет удобный способ записи данных в файл с использованием сгенерированного класса.

1 голос
/ 31 декабря 2010

Эта проблема лучше всего решается с помощью SAX.В .NET есть несколько реализаций SAX, хотя мне бы хотелось, чтобы в .NET была нативная реализация.

Проблема в том, что у вас есть только два цикла for, максимум, что вы сможете сделать, это двауровни.Это может быть утомительно, чтобы продолжать добавлять дополнительные для циклов.Есть лучший шаблон.

Если бы вы не использовали SAX, вам нужно создать универсальный движок, который может обрабатывать любое количество ворот внутри ворот.

Это было бы что-то вродеэто

 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);
           }
      }
 }

Я сильно упрощаю это.Если вы хотите создать это правильно, используйте шаблон Visitor .По сути, это то, что сделал бы двигатель SAX.Это позволит вам «посещать» каждый элемент в документе и предпринимать некоторые заранее определенные действия, когда вы достигнете элемента.

Примерно так

Если я достигну стратегии, сохраню ее имя и установлю поле состояния, в котором говорится, что я в стратегии.Однажды я попал в хранилище информации о них, но пока не создаю массив правил.Если я попаду в новые ворота, перенесу эту новую операцию в стек.Если я нажму на правило, создай новый массив правил и свяжи его с самыми верхними воротами.

1 голос
/ 31 декабря 2010

Я бы создал объект стратегий, который содержит список объектов стратегии. Объект стратегии должен содержать объект Gate и т. Д., А затем сериализовать XML в экземпляр этих объектов. Вы можете столкнуться с проблемами сериализации этого XML, потому что он не является единообразным. Вам нужно будет включить элемент Gates как дочерний элемент элемента Gate, чтобы вы могли включить свой список объектов Gate ...

Пример без вложенных ворот ...

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

Пример с вложенными воротами ...

<Gate>
  <Gates>
    <Gate>
      <Gates>
      </Gates>
      ...
    </Gate>
  </Gates>
  ...
</Gate>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...