| 

.NET C# Java Javascript Exception

4
Gegeben ist folgende XML-Datei:
<topic id="topic_id">
<title>Hello World</title>
<body>
<p>Text, more Text, even more Text...</p>
</body>
</topic>

Es kann aber auch vorkommen das im Body mehrere <p>-Tags vorhanden sind. Daraus soll ein Object Tree erstellt werden über den anschließend Iteriert werden können soll. Die aktuelle Idee sieht wie folgt aus:

Parser:
DataModelBuilder dmBuilder = new DataModelBuilder();

public DitaFile parseDitaDocument(string fileName)
{
DitaFile ditaFile = new DitaFile();

XmlDocument doc = new XmlDocument();
//Ignore DTD
doc.XmlResolver = null;
doc.Load(@"O:\dita_test\introduction\index.dita");

parseDitaDocument(doc, ditaFile);
return ditaFile;
}

private void parseDitaDocument(XmlDocument document, Element element)
{
foreach (XmlNode innerNode in document.SelectNodes("*"))
{
switch (innerNode.Name)
{
case "topic": //<TOPIC>
Element result = dmBuilder.createTopic(innerNode);
element.AddChild(result);
parseTopicNode(innerNode, result);
break;
default:
Console.WriteLine(innerNode.Name + " is not supported here!");
break;
}
}
}

private void parseTopicNode(XmlNode node, Element element)
{
foreach (XmlNode innerNode in node.SelectNodes("*"))
{
switch (innerNode.Name)
{
case "title": // <TITLE>
element.AddChild(dmBuilder.createTitle(innerNode));
//NOTE: title has no children
break;
case "body": // <BODY>
Element result = dmBuilder.createBody(innerNode);
element.AddChild(result);
parseBody(innerNode, result);
break;
default:
Console.WriteLine(innerNode.Name + " is not supported here!");
break;
}
}
}


Builder:
public Topic createTopic(XmlNode node)
{
Topic topic = new Topic();
// Attribute : id
topic.Id = node.Attributes["id"].InnerText;
return topic;
}

public Title createTitle(XmlNode innerNode)
{
Title title = new Title();
// Content
title.Content = innerNode.InnerText;
return title;
}


Models:
interface Element
{
void AddChild(Element element);
}

class Topic : Element
{
public List<Element> children = new List<Element>();
public string Id { get; set; }
public Topic() {}

public void AddChild(Element element)
{
children.Add(element);
}
}


Später soll Mithilfe des Visitor-Pattern darüber iteriert werden und je nach Objekt eine bestimmte Transformation ausgeführt werden.

Nun zur Frage: Hat jemand Vorschläge wie der Code einfach wartbarer, erweiterbarer oder ähnliches werden könnte? Bin für jeden Ratschlag wirklich Dankbar da ich erst vor kurzem mit C# angefangen habe.
15.08.2011
najjannaj 63 3
3 Antworten
0
Um den Code zu vereinfachen würde ich dir empfehlen dich in LinQ einzuarbeiten. Damit gelingt das Parsen von XML Dateien i.d.R. wesentlich übersichtlicher. Einen Einstieg findest du z.B. hier.
Gruß, Daniel
17.08.2011
puls200 3,8k 7
Könntest du deine Idee noch etwas ausführen, wie dies die Übersichtlichkeit steigern soll? Ich habe das Tutorial durchgelesen und soweit verstanden, aber wie ich dieses auf meinen Anwendungsfall anwenden können soll ich mir noch etwas Rätselhaft. Trotzdem schon mal vielen Dank!
najjannaj 17.08.2011
Der Vorteil liegt imho in der Lesbarkeit und Einfachheit.

Du kannst beispielsweise eine Anfrage stellen die so aussehen könnte (habe sie nicht getestet):

string topicId = 123;
var xml = XDocument.Load("source");

var topics = from topic in xml.Descandents("topic") where document.id = topicId select new
{
Title = topic.Element("title").Value,
...
};

topics ist dann eine Liste mit den gefundenen Elementen die die einzelnen Werte enthalten.

Du kannst damit auch Abfragen verschachteln, erweitern usw. ohne den Überblick in Ifs und Elses, switches und cases zu verlieren.
Hendrik Lösch 18.08.2011
0
Hallo najjannaj,

Du kannst auch XML Serialisierung verwenden, gibts quasi geschenkt. Dein Problem löst Du mit folgenden Schritten:

  • Erstelle eine .xml Datei und kopier Dein Beispiel-XML von oben rein.
  • Öffne die .xml Datei in VisualStudio und klicke im Menü XML->Schema erstellen. Damit hast Du Dir ein Schema generiert, dass Du noch an Deine Bedürfnisse anpassen kannst. Speichere es in einer Datei (z.B. MySchema.xsd)
  • Öffne einen VisualStudio CommandPrompt, wechsle in das Verzeichnis, in der Deine Schemadatei liegt und führe folgenden Befehl aus:
    xsd.exe MySchema.xsd /classes
    Das Tool xsd.exe generiert Dir daraufhin eine Datei MySchema.cs im selben Verzeichnis mit für die XML Serialisierung fertigen Klassen (partial!).
  • Nachfolgenden Code kannst Du dann nutzen, um zu de/serialisieren:

XmlSerializer serializer = new XmlSerializer(typeof(topic));
topic t = (topic)serializer.Deserialize(File.OpenText("Testdata.xml"));

t.id = "changed_topic_id";
serializer.Serialize(File.CreateText("Testdata2.xml"), t);


Das sollte Dir den Einstieg erleichtern. Wie Du die XML Serialisierung noch anpassen kannst bzw. was man mit xsd.exe und seinen Parametern noch erreicht, findest Du in der MSDN. Dort findest Du auch Informationen zu Einschränkungen bzw. Grenzen dieser Technik.

Thema Wartbarkeit/Erweiterbarkeit: Seitdem es partial Classes gibt, hast Du es leicht, "Deinen" Code vom Generierten zu trennen. Wenn sich Dein Schema ändern sollte, kannst Du die Klassen neu generieren, der restliche Code (in anderen partial Teilen) ist nur logisch von den Änderungen betroffen. Ich würde sogar soweit gehen, die Serialisierung komplett eigenständig zu lassen und nur als Persistenzoption zu nutzen. Was Du nämlich fachlich mit Deinen Topics anstellst sollte unabhängig von Ihrer Persistenz sein.

Viel Erfolg
Florian
17.08.2011
ffordermaier 8,4k 3 9
1
Wollte ich ihm auch erst vorschlagen, aber "Später soll Mithilfe des Visitor-Pattern darüber iteriert werden" habe ich dann so verstanden, dass die Entscheidung, in Topic eine List<Element> zu halten, bewußt getroffen wurde, d.h. najjannaj scheint zu wollen, dass title und body usw. gemeinsam in der Liste landen, statt sie z.B. als jeweils eigene Properties von Topic zu repräsentieren. Ob das eine gute Idee ist oder eher nicht, läßt sich nur mit mehr Kontext beurteilen. Aber falls es wirklich so sein soll, führt XML-Serialisierung hier nicht zum Ziel, fürchte ich.
Matthias Hlawatsch 17.08.2011
Aus der Perspektive hab ich das noch gar nicht betrachtet. Aber wenn die Intention tatsächlich der von Dir beschriebenen entsprechen sollte, dann könnte er (wie ich am Schluss meines Posts schon laut drüber sinniert habe) seine Fachklassen entsprechend seinen Anforderungen unabhängig von den Persistenzklassen designen und eine bidirektionale Abbildung zwischen beiden entwickeln. Damit ist er in der Wahl der Fachstruktur frei und trennt gleichzeitig Persistenz von Fachlogik. Mit etwas mehr Kontext könnten aber auch noch andere Lösungswege in Frage kommen.
ffordermaier 17.08.2011
0
Habe gerade erst gesehen, dass der Verweis schon gepostet wurde. Sorry.
18.08.2011
Hendrik Lösch 1,5k 1 9

Stelle deine .net-Frage jetzt!
TOP TECHNOLOGIES CONSULTING GmbH