Laden...

XML Datei erweitern mit verschiedenen Datensätzen

Erstellt von Shatex vor 5 Jahren Letzter Beitrag vor 5 Jahren 3.115 Views
S
Shatex Themenstarter:in
6 Beiträge seit 2015
vor 5 Jahren
XML Datei erweitern mit verschiedenen Datensätzen

verwendetes Datenbanksystem: XML

Hallo,

ich habe für meine Abschlussarbeit vor 3 Monaten mit C# Programmeriung begonnen, merke aber immer wieder das ich irgendwo hängen bleibe 😃

Ich muss mit XML Dateien arbeiten. Ich möchte eine XML Stückweise erweitern.

Problem:

Ich habe einen Funktionsbaustein (Siemens TIA Portal) exportiert als XML File. Man kann diesen Baustein nun via XML bearbeiten und ihm Netzwerke hinzufügen, in den Netzwerken andere Bausteine aufrufen oder Logik hinzufügen (Logisch AND / OR usw.) und diese Bausteine auch verdrahten.

Ich habe mir im Vorfeld andere Bausteine erzeugt, welche ich einfach aufrufen kann, wenn ich diese im XML des Hauptbausteins aufrufe.

Baustein siehe Bild Anhang 1

Der XML Code für einen Baustein sieht so aus:

 <SW.Blocks.CompileUnit ID="B" CompositionName="CompileUnits">
        <AttributeList>
          <NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v2">
  <Parts>
    <Access Scope="GlobalVariable" UId="21">
      <Symbol>
        <Component Name="ConveyorData" />
        <Component Name="driveExecute" />
      </Symbol>
    </Access>
    <Access Scope="GlobalVariable" UId="22">
      <Symbol>
        <Component Name="ConveyorData" />
        <Component Name="driveHardware" />
      </Symbol>
    </Access>
    <Access Scope="GlobalVariable" UId="23">
      <Symbol>
        <Component Name="ConveyorData" />
        <Component Name="driveParam" />
      </Symbol>
    </Access>
    <Call UId="24">
      <CallInfo Name="Drive" BlockType="FB">
        <Instance Scope="GlobalVariable" UId="25">
          <Component Name="InstDrive" />
        </Instance>
        <Parameter Name="execute" Section="Input" Type="Bool" />
        <Parameter Name="hardware" Section="Input" Type="HW_IO" />
        <Parameter Name="status" Section="Output" Type="Word" />
        <Parameter Name="driveParam" Section="InOut" Type="typeDriveParam" />
      </CallInfo>
    </Call>
  </Parts>
  <Wires>
    <Wire UId="28">
      <OpenCon UId="26" />
      <NameCon UId="24" Name="en" />
    </Wire>
    <Wire UId="29">
      <IdentCon UId="21" />
      <NameCon UId="24" Name="execute" />
    </Wire>
    <Wire UId="30">
      <IdentCon UId="22" />
      <NameCon UId="24" Name="hardware" />
    </Wire>
    <Wire UId="31">
      <NameCon UId="24" Name="status" />
      <OpenCon UId="27" />
    </Wire>
    <Wire UId="32">
      <IdentCon UId="23" />
      <NameCon UId="24" Name="driveParam" />
    </Wire>
  </Wires>
</FlgNet></NetworkSource>

Interessant wird es bei <Parts> und <Wires>. Dort findet die eigentliche Verschaltung statt.

Nun habe ich verschiedene Bausteine und immer wieder eine unterschiedliche Anzahl an Bausteinen die ich ergänzen möchte, sprich mal sind es 4x Typ A Bausteine, 2x Typ B Bausteine usw.

Je nach nach Art und Anzahl der Bausteine muss ich meine Haupt XML Datei (Hauptbaustein) ergänzen.

Ergebis soll zum Schluss z.B. so aussehen: (hier mit anderen Bausteinen "Conveyor")

Bild Anhang 2

Es wurden 3 Netzwerke mit Bausteinen ergänzt, welche mit C# verschalten sind(Parts/Wires)

Der Hersteller stellt für alle Teilbereiche der XML verschiedene Schemas (XSD) zur Verfügung, nur verstehe ich es bisher nicht richtig wie das mit den XSD funktioniert. Validiere ich damit Daten, oder kann ich das jeweilige Schema "laden und einfügen" um es anschließend mit C# mit den variablen Daten zu beschreiben?

In einem Beispiel von Siemens wird auf eine XML Datei zugegriffen, welche schon über den maximalen Ausbau der Anlage verfügt, sprich es wird einfach die Anzahl der benötigten Bausteine und Netzwerke gezählt und diese gelöscht.

Ich benötige erstmal eine Herangehensweise an diese Sache. XML öffnen einlesen etc klappt bisher. Wie ich die Daten beschreibe, hab ich denke ich auch verstanden.

Nur wie ich mir die Vorlagen mit dem XML Snippets einfüge verstehe ich nicht ganz (Stichwort Vorlagen?)
Vielen Dank!

S
Shatex Themenstarter:in
6 Beiträge seit 2015
vor 5 Jahren
16.828 Beiträge seit 2008
vor 5 Jahren

nur verstehe ich es bisher nicht richtig wie das mit den XSD funktioniert.

XML Verarbeitung gehört zu den mit am besten dokumentierten Elementen im gesamten Microsoft Docs - zudem ist die Verbreitung von XML gigantisch. Dass Du da wirklich nichts gefunden hast....

Die Fragen insgesamt deuten darauf hin, dass Du nicht viel aktive Zeit in dieses Thema gesteckt haben kannst 😉

Validiere ich damit Daten, oder kann ich das jeweilige Schema "laden und einfügen" um es anschließend mit C# mit den variablen Daten zu beschreiben?

Wie sicherlich dem Wiki zu entnehmen ist, ist XSD einzig und allein zur Definition einer Struktur gedacht; daher auch der Name und die Bezeichnung XML Schema.

Bei der Validierung wird zum einen das XSD gebraucht und zum andern das XML.
Das XSD wird dazu verwendet, um die Struktur einer XML Datei zu validieren.

Das XSD kann aber auch für andere Dinge verwendet werden, zB durch die strukturelle Vorgabe als IntelliSense Quelle in XML Editoren.

Nur wie ich mir die Vorlagen mit dem XML Snippets einfüge verstehe ich nicht ganz (Stichwort Vorlagen?)

Was sind XML Snippets? 🤔

5.299 Beiträge seit 2008
vor 5 Jahren

Ach Abt - immer ein aufmunterndes Wort für die Anfänger! 😉

Und so unwidersprüchlich:

Wie sicherlich dem Wiki zu entnehmen ist, ist XSD einzig und allein zur Definition einer Struktur gedacht (ähm - welchem Wiki?)
Das XSD kann aber auch für andere Dinge verwendet werden, zB durch die strukturelle Vorgabe als IntelliSense Quelle in XML Editoren.

Und ich hätte noch ein, wofür man Xsd gebrauchen kann: Man kann sich damit eine Klassen-Struktur generieren lassen. Ich hab zwar grad vergessen wie das im Einzelnen geht, aber google "c#-Classes from xsd" müsste Anleitung erbringen.

Hat man diese Klassen-Struktur, so kann man eine Xml deserialisieren (Stichwort "Xml-Serialisierung"), und enhält c#-Objekte, die man mit c# manipulieren kann, und das Ergebnis kann man auch wieder serialisieren.
Auf diese Weise muss man mit Xml überhaupt nicht herumfuchteln, sondern es ist ein Instrument, um sehr komplexe Objektstrukturen zu persistieren oder zu transportieren.

Der frühe Apfel fängt den Wurm.

16.828 Beiträge seit 2008
vor 5 Jahren

Ach Abt - immer ein aufmunterndes Wort für die Anfänger! 😉

😭

Ich hab zwar grad vergessen wie das im Einzelnen geht, aber google "c#-Classes from xsd" müsste Anleitung erbringen.

Einfach mit der XSD.exe, die mit Visual Studio mitkommt.
Dazu braucht man prinzipiell aber keine XSD, dazu reicht auch eine XML, mit der es noch einfacher geht Edit -> Paste Special -> Paste as C# Class
Die XSD macht auch keine perfekte Klassenstruktur.

S
Shatex Themenstarter:in
6 Beiträge seit 2015
vor 5 Jahren
<?xml version="1.0" encoding="utf-8"?>
<Interface>
  <Sections xmlns="http://www.siemens.com/automation/Openness/SW/Interface/v3">
    <Section Name="Static">
      <Member Name="C004" Datatype="&quot;typeConveyorDrive&quot;" Remanence="NonRetain" Accessibility="Public">
        <AttributeList>
          <BooleanAttribute Name="ExternalAccessible" SystemDefined="true">true</BooleanAttribute>
          <BooleanAttribute Name="ExternalVisible" SystemDefined="true">true</BooleanAttribute>
          <BooleanAttribute Name="ExternalWritable" SystemDefined="true">true</BooleanAttribute>
        </AttributeList>
      </Member>
    </Section>
  </Sections> 
</Interface>

Hallo,

danke für die ANtworten, aber ich verstehe es einfach nicht!

Ich lade ein XElement

XElement PlantConfigDB = XElement.Load(@"C:\Users\XXXX\Desktop\PlantConfigDataTera.xml");

Wie kann ich in der XML oben jetzt ab <Member> die Daten löschen inkl Subchilds? Ich habe es mit XElement, XDocument versucht.

Ergebnis sollte so sein:

<?xml version="1.0" encoding="utf-8"?>
<Interface>
  <Sections xmlns="http://www.siemens.com/automation/Openness/SW/Interface/v3">
    <Section Name="Static">
      
    </Section>
  </Sections> 
</Interface>

Es steht in der Doku:

root.Element("Child1").Element("GrandChild1").Remove();  

Aber wie kann ich in einer großen XML Datei bis zum Element navigieren? Muss ich dazu den kompletten Pfad in der XML angeben (wäre sehr umständlich) bzw im Moment funktioniert es auch mit dieser Methode nicht

PlantConfigDB.Element("Interface").Element("Sections").Element("Member").Remove();

Mit einer LINQ Abfrage klappt es nie, da mir immer null zurückgegeben wird:

var q =

 from el in PlantConfigDB.ElementsAfterSelf("Section")
 select el;

Anschließend würde ich gern NACH <Section> einen XML Block anfügen. Bisher klappt es nur am Ende der Datei mit:

PlantConfigDB.AddAfterSelf(Member);

Zurückschreiben klappt auch mit

PlantConfigDB.Save(@"C:\Users\...\Desktop\PlantConfigDataTera.xml");
T
2.222 Beiträge seit 2008
vor 5 Jahren

@Shatex
Wie groß sind den deine XML Dateien?
Wenn es recht kleine sind, könntest du auch mit XmlDocument arbeiten.
Dort kannst du via XPath auch per SelectNodes und dem passenden XPath dann alle Member Tags suchen, die unter Interfaces/Sections die Members suchen und aus dem XmlDocument entfernen lassen.
Dann kannst du dein angepasstest XmlDocument auch gleich wieder speichern lassen.
Ich kann mir auch nicht vorstellen, dass du dir die Doku angeschaut und dann mal etwas rumgetestet hast.
Mit der Doku und Google findest du zum bearbeiten von XML Dateien mit C# unmengen an Beispielen.
Gerade sowas simples wie dem bearbeiten von XML Dateien kann man bei Google massig Beispiele finden.
Hier musst du auch etwas Eigeninitative zeigen und dich mit der Doku beschäftigen!
Gerade die C# API Doku kann dir ungemein viel Arbeit sparen, da du meistens das Rad nicht neuerfinden musst und .NET dir vieles fertig liefert.
Vielleicht nicht immer als performanteste Lösung aber damit hast du einen guten Start.

Zu beachten ist auch, dass deine Sections einen XML Namespace(xmlns Attribut) haben.
Diese musst du beim auslesen der Nodes und auch bei den anderen X* Klassen meistens mit angeben, sonst werden diese wegen dem Default Namespace nicht gefunden.
Auch XML kann seine Daten per Namensräume abtrennen!

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

5.658 Beiträge seit 2006
vor 5 Jahren

Ich glaube nicht, daß es eine gute Idee ist, das XML-Dokument direkt zu manipulieren. Besser wäre, die Daten aus der XML-Datei zu lesen, die Daten zu manipulieren und dann wieder in eine XML-Datei zu schreiben. Wie das geht, wurde ja schon gesagt:

Edit -> Paste Special -> Paste as C# Class

Hat man diese Klassen-Struktur, so kann man eine Xml deserialisieren (Stichwort "Xml-Serialisierung"), und enhält c#-Objekte, die man mit c# manipulieren kann, und das Ergebnis kann man auch wieder serialisieren.
Auf diese Weise muss man mit Xml überhaupt nicht herumfuchteln, sondern es ist ein Instrument, um sehr komplexe Objektstrukturen zu persistieren oder zu transportieren.

Weeks of programming can save you hours of planning

3.003 Beiträge seit 2006
vor 5 Jahren

Entfernen von Knoten ist ziemlich trivial. Da kann man eigentlich nur die Lösung posten:


using (var inStream = File.Open("source.xml", FileMode.Open))
using (var outStream = File.Open("destination", FileMode.Create))
{
    var xDoc = XDocument.Load(inStream);
    xDoc.Root.Descendants("Section").SelectMany(p => p.Elements()).ToList().ForEach(p => p.Remove());
    xDoc.Save(outStream);
}

(Nebenbei bemerkt, ist die Benutzung von XmlDocument völlig unberührt von der Größe der XML-Datei.)

LaTino
EDIT: @ErfinderDesRades, MrSparkle: klar habt ihr recht. Aber wenn es darum geht, optionale Knoten hinzuzufügen oder zu entfernen, muss man sich schon ziemlich gut auskennen, um den XmlSerializer das tun zu lassen, was man möchte. Wenn man sich gut auskennt, ist das sicher der bessere Weg. Ich habe aber den Eindruck, dass hier das XML das Ziel ist, und nicht das deserialisierte Objekt.

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

S
Shatex Themenstarter:in
6 Beiträge seit 2015
vor 5 Jahren

Hallo,

erstmal Danke für die Antworten. Diese "triviale" Lösung funktioniert nicht oder ich mache etwas falsch.

    using (var inStream = File.Open(@"C:\Users\XXX\Desktop\PlantConfigDataTera.xml", FileMode.Open))
        using (var outStream = File.Open(@"C:\Users\XXX\Desktop\PlantConfigDataTeraXXXX.xml", FileMode.Create))
        {
            var xDoc = XDocument.Load(inStream);
            xDoc.Root.Descendants("Section").SelectMany(p => p.Elements()).ToList().ForEach(p => p.Remove());
            xDoc.Save(outStream);
        }

Mir wird eine weitere XML erzeugt mit gleichem Inhalt. Das mit dem Serialisieren in C# Klassen ist ja ganz nett, aber geht es nicht auch über den XElement Weg? Wie sieht es aus mit LINQ?

Meine XML Dateien sind so ~2MB groß. Ja ich finde unmengen an Beispielen, aber es funktioniert einfach nichts davon. Scheinbar mache ich etwas elementar falsch. Und jetzt kommt mir nicht mit Eigeninitiative bitte, ich durchforste die ganzen StackOverflow Beiträge seit Tagen.

DIe Doku LINQ mit XML hab ich durch. Welche Doku soll ich noch lesen?

Danke

S
248 Beiträge seit 2008
vor 5 Jahren

Zu beachten ist auch, dass deine Sections einen XML Namespace(xmlns Attribut) haben.
Diese musst du beim auslesen der Nodes und auch bei den anderen X* Klassen meistens mit angeben, sonst werden diese wegen dem Default Namespace nicht gefunden.


XNamespace nse = "http://www.siemens.com/automation/Openness/SW/Interface/v3";
xDoc.Root.Descendants(nse + "Section").SelectMany(p => p.Elements()).ToList().ForEach(p => p.Remove());

Grüße

S
Shatex Themenstarter:in
6 Beiträge seit 2015
vor 5 Jahren

Da ist er, mein Held des Tages. Das hab ich komplett übersehen! Danke!

Jetzt funktioniert alles 😃