【问题标题】:Problem in parsing XML file解析XML文件的问题
【发布时间】:2010-12-31 16:56:04
【问题描述】:

我有以下 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 文件,而不是第二个示例中的另一个门。但是我无法解析嵌套的门。任何提示从哪里开始?

【问题讨论】:

    标签: c# .net wpf xml


    【解决方案1】:

    使用 XDocument 或 XmlDocument 解析 XML 会很脆弱。

    我建议你设计一个对象模型来满足这种结构和逻辑,并使用 XML 序列化/反序列化来持久化或水合。

    归根结底,这种 XML 表示只是您的逻辑的一种可能表示,您可以将它们作为 JSON、二进制...

    一个例子:

    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;}
        // ...
    }    
    

    更新

    这是你的序列化方式(简单易懂)

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

    【讨论】:

      【解决方案2】:

      我将创建一个包含策略对象列表的策略对象。策略对象将包含 Gate 对象等,然后将 XML 序列化为这些对象的实例。您可能会遇到序列化该 xml 的问题,因为它不统一。您必须包含 Gates 元素作为 Gate 元素的子元素,以便您可以包含 Gate 对象列表...

      没有嵌套门的示例...

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

      嵌套门的示例...

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

      【讨论】:

        【解决方案3】:

        这个问题似乎最好使用 SAX 解决。 .NET 中有一些 SAX 的实现,尽管我希望 .NET 中有一个本机实现。

        问题是你只有两个 for 循环,你最多可以下两层。继续添加额外的 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 引擎会做的事情。这将允许您“访问”文档中的每个元素,并在您到达该元素时采取一些预定义的操作。

        类似的东西

        如果我到达一个策略存储它的名称并设置一个状态字段说我在一个策略中。一旦我击中一个门,就会存储有关该门的信息,但还没有创建规则数组。如果我击中一个新的门,则将该新操作推入堆栈。如果我点击了一条规则,则创建一个新的规则数组并将其与最顶层的门相关联。

        【讨论】:

          【解决方案4】:

          如果您可以访问 XML 文件的 XSD 定义,则可以使用 Visual Studio 附带的 xsd.exe 实用程序自动生成 C# 类来处理 XML 文件。使用生成的 C# 代码,您将能够将 de XML 加载到一个内存结构中,该内存结构可以作为具有您可以将其视为任何其他集合的属性的项目集合轻松访问。

          此方法还提供了一种使用生成的类将数据写入文件的便捷方式。

          【讨论】:

          • 谢谢。但我在我的系统上找不到和 xsd.exe。
          • @Rodflcoptr 您可以在\Program files\Windows SDKs 的Windows SDK 目录中找到xsd.exe 实用程序,您可以在以下链接中找到信息stackoverflow.com/questions/1073228/…
          • 是的,这是正确的,我已经在文档中看到了。我的问题是那里没有 xsd.exe。然后我在整个系统中搜索了这个文件,但找不到。现在我正在寻找下载它的地方。
          • 我不知道这篇文章的真实性如何 (haiders.net/post/Download-xsdexe.aspx),但似乎 xsd.exe 不再随 Visual Studio 一起提供。
          猜你喜欢
          • 2023-03-25
          • 1970-01-01
          • 2017-04-21
          • 1970-01-01
          • 1970-01-01
          • 2012-01-29
          • 1970-01-01
          • 1970-01-01
          • 2012-08-01
          相关资源
          最近更新 更多