2011-11-30 5 views
0

Мне нужно извлечь информацию из входящих (например, 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); 

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

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

$id,$posX,$posY,$posZ 

и поступающие данные будут затем

1,0.5f,1.0f,0.0f 

В последнем случае может быть eaiser для синтаксического анализа, но мне нужно решение, которое способно дескриптор как (шаблон xml, так и не xml).

+2

[LINQ к XML] (http://msdn.microsoft.com/en-us/library/bb387098.aspx), вероятно, лучший API для этого. – Oded

ответ

1

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

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

Спасибо, но он должен быть более гибким. Проблема заключается в том, что шаблон XML может измениться (например, «Позиция» изменится на «» Pos », или некоторые дети будут добавлены в« Позиция »). Также формат шаблона не должен основываться на XML, поэтому я ищу более например, с использованием функций соответствия regex/string. – user819068

+0

Этот метод был настроен для создания классов, которые могут быть использованы в приложении, чтобы определить структуру объекта, входящего в состав. Когда структура меняется регулярно, я бы предложил linq для xml , например oded предложил – dannl

+0

Да, это возможно или может измениться в будущем. Я не уверен, как использовать linq для xml для извлечения информации из входной строки на основе определения шаблона и переменной, может быть, у кого-то есть пример. – user819068

0

Возможно, было бы неплохо использовать интерфейс и 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); 
} 
} 
0

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

Parser типа (XML или CSV)

Variable1, путь

variable2, путь

и т.д.

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

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

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

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

0
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 
Смежные вопросы