Разбор / извлечение информации из текстового шаблона - PullRequest
0 голосов
/ 30 ноября 2011

Мне нужно извлечь информацию из входящих (например, XML) данных на основе данного шаблона.Шаблон может быть XML или простым текстом (через запятую).Для каждого типа сообщения существует шаблон, например,

<SomeMessage>
    <Id>$id</Id>
    <Position>
        <X>$posX</X>
        <Y>$posY</Y>
        <Z>$posZ</Z>
    </Position>
</SomeMessage>

Например, входящие данные:

<SomeMessage>
    <Id>1</Id>
    <Position>
        <X>0.5f</X>
        <Y>1.0f</Y>
        <Z>0.0f</Z>
    </Position>
</SomeMessage>

Теперь мне нужно извлечь информацию о $ id, $ posX и т. Д..

Parser p = new Parser(templateString);
int id = p.Extract("id", incomingString);
float posx = p.Extract("posX", incomingString);

Мне нужно что-то вроде различия входящих данных и шаблона, а затем извлечь информацию на подходящей позиции.Поскольку существует несколько шаблонов, которые содержат различную информацию и могут быть расширены в будущем, я ищу общий подход.

Шаблон в этом случае также может быть

$id,$posX,$posY,$posZ

и входящийтогда данные будут

1,0.5f,1.0f,0.0f

Последний случай может быть проще для анализа, но мне нужно решение, которое может обрабатывать как (шаблон XML, так и не XML).

Ответы [ 4 ]

1 голос
/ 30 ноября 2011

Вы можете создать класс синтаксического анализа, имеющий свойство для каждого поля:

class Parser
{
    public string PositionX { get; set; }
    public string PositionY { get; set; }
    public string PositionZ { get; set; }

    public Parser(XmlNode item)
    {
        this.PositionX = GetNodeValue(item, "Position/X");
        this.PositionY = GetNodeValue(item, "Position/X/Y");
        this.PositionZ = GetNodeValue(item, "Position/X/Y/Z");
    }
}

Я могу предоставить процедуру, которая может генерировать такие классы синтаксического анализа из образца xml, если вам интересно, когда массивы не имеют значения.GetNodeValue - это метод, который использует запрос xpath и возвращает значение для xpath (в основном, XmlNode.SelectSingleNode с добавленным к нему добавленным синтаксическим анализом).

0 голосов
/ 30 ноября 2011
using System;
using System.IO;
using System.Xml;

class TemplateParse {
    XmlDocument xdoc;

    string GetPath(XmlNode node, string val, string path){
        if(node.HasChildNodes){
            if(node.ChildNodes.Count == 1 && node.FirstChild.NodeType == XmlNodeType.Text)
                return (node.FirstChild.Value == val) ? path + "/" + node.Name : String.Empty;
            foreach(XmlNode cnode in node.ChildNodes){
                if(cnode.NodeType != XmlNodeType.Element) continue;
                string result = GetPath(cnode, val, path + "/" + node.Name);
                if(result != String.Empty) return result;
            }
        }
        return "";
    }
    public TemplateParse(string templateXml){
        xdoc = new XmlDocument();
        xdoc.LoadXml(templateXml);
    }
    public string Extract(string valName, string data){
        string xpath =  GetPath((XmlNode)xdoc.DocumentElement, "$" + valName, "/");
        var doc = new XmlDocument();
        doc.LoadXml(data);
        return  doc.SelectSingleNode(xpath).InnerText;
//      var value = doc.SelectSingleNode(xpath).InnerText;
//      var retType = typeof(T);
//      return (T)retType.InvokeMember("Parse", System.Reflection.BindingFlags.InvokeMethod, null, null, new []{value});
    }
}

class Sample {
    static void Main(){
        string templateString = File.ReadAllText(@".\template.xml");
        string incomingString = File.ReadAllText(@".\data.xml");

        var p = new TemplateParse(templateString);

        string[] names = new [] { "id", "posX", "posY", "posZ" };
        foreach(var name in names){
            var value = p.Extract(name, incomingString);
            Console.WriteLine("{0}:{1}", name, value);
        }
    }
}

ВЫХОД

id:1
posX:0.5f
posY:1.0f
posZ:0.0f
0 голосов
/ 30 ноября 2011

Для каждого шаблона создайте файл определения анализатора в формате:

Тип синтаксического анализатора (XML или CSV)

Переменная1, путь

переменная 2, путь

и т.д.

для пути xml может быть someMessage, Position, x.

для csv вы можете забыть путь и просто перечислить переменные по порядку.

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

Для всего, что связано с CSV, вам, вероятно, придется использовать парсер, но для XML / XPATH довольно просто найти основы.

0 голосов
/ 30 ноября 2011

Вероятно, было бы неплохо использовать интерфейс и 2 разных шаблона для каждого случая. Обратите внимание, что возвращаемое Сообщение не завершено, но оно дает вам представление. Со статическим XElement.Parse вы можете анализировать правильно сформированные строки XML для более удобного использования.

public interface IParser
{
    Message Parse(String Payload);
}
 // Position Class
 public class Position
 {
 public int X { get; private set; }
 public int Y { get; private set; }
 public int Z { get; private set; }
 public Position(int X, int Y, int Z)
 {
  this.X = X;
  this.Y = Y;
  this.Z = Z;
 }
}
// Message Class 
public class Message
{
 public String ID { get; private set; }
 public Position Position { get; private set; }
 public Message(String ID, Position Position)
 {
   this.ID = ID;
   this.Position = Position;
 }
}
 // Parser Class
 public class XMLParser : IParser
{
 public Message Parse(string Payload)
 {
  var result = XElement.Parse(Payload);
  return new Message(result.Elements().ElementAt(0).Value, new Position(X,Y,Z);
 }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...