XML-Knoten untereinander anordnen

  • Allgemein

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von Ruzbacky.

    XML-Knoten untereinander anordnen

    Guten Abend zusammen,

    ​vorweg muss ich sagen, dass ich mich mit XML nur sehr rudimentär auskenne und deswegen auch nicht verstehe warum eben genau das passiert, was ich nicht verstehe.

    ​Ich habe ein AddIn für unsere CAD-Software in VB.NET geschrieben, welches unteranderem Stücklisten in ein XML-File exportiert.
    ​Dies funktioniert soweit auch sehr gut, bis auf dass sich der Export der Informationen in das XML-File, bzw. die darin enthaltenen Knoten mir unerklärlich verhalten.

    ​Bei meines Erachtens nach identischem Code erscheinen die Knoten mal so:

    XML-Quellcode

    1. <Commission>55555</Commission>
    2. <Project>BOM-Projekt</Project>
    3. <Customer>Test</Customer>

    und mal so:

    XML-Quellcode

    1. <ItemNumber />1<Quantity />1<Revision />0


    Die gesamte XML sieht so aus:
    Spoiler anzeigen

    XML-Quellcode

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <BillOfMaterial>
    3. <AssemblyInformation>
    4. <Commission>55555</Commission>
    5. <Project>BOM-Projekt</Project>
    6. <Customer>Test</Customer>
    7. <Description>Abstandhalter</Description>
    8. <DrawingNumber>55555-01-001</DrawingNumber>
    9. <RevisionNumber>0</RevisionNumber>
    10. <Author>MR</Author>
    11. <Date>09.12.2017</Date>
    12. </AssemblyInformation>
    13. <Components>
    14. <Component DocId="956977927">
    15. <ItemNumber />1<Quantity />1<Revision />0<PartNumber />55555-02-001<DescriptionDe />Scheibe<DescriptionEn />Plate<Dimensions />t10 Ø250<Material />S235JR<Standard />EN 10025-2<Certificate />3.1 ADW1<Weight />3,88<StockNumber /><DocId />956977927</Component>
    16. <Component DocId="887839426">
    17. <ItemNumber />2<Quantity />1<Revision />0<PartNumber />55555-02-002<DescriptionDe />Bolzen<DescriptionEn />Bolt<Dimensions />Ø30 - 150<Material />S235JR<Standard />EN 10060<Certificate />2.2<Weight />0,84<StockNumber /><DocId />887839426</Component>
    18. <Component DocId="861080793">
    19. <ItemNumber />3<Quantity />1<Revision />0<PartNumber />55555-02-003<DescriptionDe />Platte<DescriptionEn />Plate<Dimensions />t5 150x150<Material />1.4301<Standard />EN 10028-7<Certificate />3.2 ADW2<Weight />0,9<StockNumber /><DocId />861080793</Component>
    20. </Components>
    21. </BillOfMaterial>


    ​Der VB.NET Code so (gekürzt):
    Spoiler anzeigen

    VB.NET-Quellcode

    1. ​Imports Inventor
    2. Imports System.Windows.Forms
    3. Imports System.Xml
    4. Public Class frmBomExport
    5. Private Sub cmdExport_Click(sender As Object, e As EventArgs) Handles cmdExport.Click
    6. #Region "XML Assembly-Information"
    7. 'Create XML and write Assembly-Information to XML
    8. Dim xmlDoc As New XmlDocument
    9. Dim xmlDeclaration As XmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", Nothing)
    10. xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement)
    11. Dim BOMNode As XmlElement = xmlDoc.CreateElement("BillOfMaterial")
    12. xmlDoc.AppendChild(BOMNode)
    13. Dim AssemblyNode As XmlElement = xmlDoc.CreateElement("AssemblyInformation")
    14. BOMNode.AppendChild(AssemblyNode)
    15. Dim ComponentsNode As XmlElement = xmlDoc.CreateElement("Components")
    16. BOMNode.AppendChild(ComponentsNode)
    17. Dim CommissionNode As XmlElement = xmlDoc.CreateElement("Commission")
    18. AssemblyNode.AppendChild(CommissionNode)
    19. Dim CommissionTextElement As XmlText = xmlDoc.CreateTextNode(CStr(cINI.INI_ReadValueFromFile("ProjectInfo", "Commission", "", strProjectINI)))
    20. CommissionNode.AppendChild(CommissionTextElement)
    21. Dim ProjectNode As XmlElement = xmlDoc.CreateElement("Project")
    22. AssemblyNode.AppendChild(ProjectNode)
    23. Dim ProjectTextElement As XmlText = xmlDoc.CreateTextNode(CStr(cINI.INI_ReadValueFromFile("ProjectInfo", "Project", "", strProjectINI)))
    24. ProjectNode.AppendChild(ProjectTextElement)
    25. Dim CustomerNode As XmlElement = xmlDoc.CreateElement("Customer")
    26. AssemblyNode.AppendChild(CustomerNode)
    27. Dim CustomerTextElement As XmlText = xmlDoc.CreateTextNode(CStr(cINI.INI_ReadValueFromFile("ProjectInfo", "Customer", "", strProjectINI)))
    28. CustomerNode.AppendChild(CustomerTextElement)
    29. #End Region
    30. #Region "BOM Components-Information"
    31. 'BOM-Export
    32. For i = 1 To oBomRows.Count
    33. Dim ComponentNode As XmlElement = xmlDoc.CreateElement("Component")
    34. Dim ComponentAttribute As XmlAttribute = xmlDoc.CreateAttribute("DocId")
    35. ComponentAttribute.Value = CStr(oCompDefUseProps.Item("Dok-ID").Value)
    36. ComponentsNode.AppendChild(ComponentNode)
    37. ComponentNode.Attributes.Append(ComponentAttribute)
    38. Dim ItemNumberNode As XmlElement = xmlDoc.CreateElement("ItemNumber")
    39. ComponentNode.AppendChild(ItemNumberNode)
    40. Dim ItemNumberTextElement As XmlText = xmlDoc.CreateTextNode(CStr(oBomRow.ItemNumber))
    41. ComponentNode.AppendChild(ItemNumberTextElement)
    42. Dim QuantityNode As XmlElement = xmlDoc.CreateElement("Quantity")
    43. ComponentNode.AppendChild(QuantityNode)
    44. Dim QuantityTextElement As XmlText = xmlDoc.CreateTextNode(CStr(oBomRow.ItemQuantity))
    45. ComponentNode.AppendChild(QuantityTextElement)
    46. Dim RevisionNode As XmlElement = xmlDoc.CreateElement("Revision")
    47. ComponentNode.AppendChild(RevisionNode)
    48. Dim RevisionTextElement As XmlText = xmlDoc.CreateTextNode(CStr(oCompDefSumProps.Item("Revision Number").Value))
    49. ComponentNode.AppendChild(RevisionTextElement)
    50. Next
    51. #End Region
    52. 'Save the XML-Document
    53. xmlDoc.Save(strWorkspacePath & "\Stücklisten\XML\" & CStr(oUseProps.Item("Zeichnungsnummer").Value) & " - " & CStr(oRefDesProps.Item("Description").Value) & ".xml")
    54. End Sub
    55. End Class


    ​Die Werte der Knoten kommen aus dem Namespace der CAD-Software, sollten jedoch für mein Problem nicht weiter von Bedeutung sein.

    ​Kann mir jemand erklären warum die Knoten mal schön sauber untereinander angeordnet werden und mal in Kurzform hintereinander?

    Ruzbacky schrieb:

    <ItemNumber />1<Quantity />1<Revision />0
    Das sieht mir sehr fehlerhaft aus.
    Es handelt sich um leere Elemente, und zwischen den Elementen findet sich Text, ohne Bezug zu irgendwas.
    Ebensogut könnte da stehen<ItemNumber /><Quantity /><Revision />110
    Also es scheint mir wirklich Blödsinn zu sein.
    Wenn das erfolgreich verarbeitet wird (bezweifel ich - ist aber theoretisch möglich), dann mit iwelchen Spezial-Parsern - nicht mit üblichem Xml-Instrumentarium, und nicht nach üblichen Xml-Konventionen.

    Ah - du bist es selbst, der den Xml-Code generiert - nun: er wird so wohl nicht von anderen Anwendungen verarbeitet werden können.

    probierma dieses:

    VB.NET-Quellcode

    1. Dim ItemNumberNode As XmlElement = xmlDoc.CreateElement("ItemNumber")
    2. ComponentNode.AppendChild(ItemNumberNode)
    3. Dim ItemNumberTextElement As XmlText = xmlDoc.CreateTextNode(CStr(oBomRow.ItemNumber))
    4. ItemNumberNode.AppendChild(ItemNumberTextElement)
    Siehst du den Unterschied?

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Oh Oh!
    Manchmal sieht den Wald in der Tat vor lauter Bäumen nicht.

    @ErfinderDesRades
    Du hast natürlich vollkommen recht, wobei ich zugeben muss, dass ich fast 5 Minuten auf deinen Code starren musste, bis mir des Rätsels Lösung offensichtlich wurde.
    Ich Danke dir für deine Hilfe, so funktioniert es natürlich :)

    ErfinderDesRades schrieb:

    Deinen Code kann man übrigens stark vereinfachen. Kannst du Extension-Methods verwenden, oder täte dich interessieren, es zu erlernen?
    Weil deinen Fehler kann man auch darauf zurückführen, dass dein Code unübersichtlich ist - da übersieht man halt leicht was.


    ​An der Vereinfachung meines Codes bin ich immer interessiert und wenn man dadurch sogar noch neues Wissen erlangen kann, welches einem auch in Zukunft noch nützlich sein wird, dann umso mehr.

    ​Also wäre ich dir für jede erdenkliche Hilfe und Anleitung sehr dankbar.
    ok, dann füge deim Projekt folgendes kleine Modul hinzu:

    VB.NET-Quellcode

    1. Imports System.Xml
    2. Imports System.Runtime.CompilerServices
    3. Public Module XmlDocumentX
    4. ''' <summary> Fügt ein XmlElement in xel ein, und returnt es </summary>
    5. <Extension()> _
    6. Public Function AppendElement(xel As XmlNode, tagName As String) As XmlElement
    7. AppendElement = xel.OwnerDocument.CreateElement(tagName)
    8. xel.AppendChild(AppendElement)
    9. End Function
    10. ''' <summary> Fügt einen Textnode in xel ein, returnt ihn aber nicht (weil man eh nix mit weiterverarbeiten kann) </summary>
    11. <Extension()> _
    12. Public Sub AppendText(xel As XmlNode, text As String)
    13. xel.AppendChild(xel.OwnerDocument.CreateTextNode(text))
    14. End Sub
    15. ''' <summary> Fügt ein XmlAttribute in xel ein, returnt ihn aber nicht (weil man eh nix mit weiterverarbeiten kann) </summary>
    16. <Extension()> _
    17. Public Sub AppendAttribute(xel As XmlNode, attrName As String, value As String)
    18. Dim attr = xel.OwnerDocument.CreateAttribute(attrName)
    19. attr.Value = value
    20. xel.Attributes.Append(attr)
    21. End Sub
    22. End Module
    Die Methoden darin sind "Extension-Methods" - oder Deutsch: "Erweiterungs-Methoden". Google den Begriff, oder lies in deim Programmierhandbuch. Und gugge auch: Extensions und mehr.

    Also mithilfe dieses Erweiterungs-Methoden-Moduls hast du die XmlNode-Klasse um 3 sehr praktische Methoden erweitert, und der Code aus post#1 kann nun wie folgt aussehen:

    VB.NET-Quellcode

    1. Private Sub cmdExport_Click(sender As Object, e As EventArgs) Handles cmdExport.Click
    2. Dim xmlDoc As New XmlDocument
    3. Dim xmlDeclaration As XmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", Nothing)
    4. xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement)
    5. Dim BOMNode = xmlDoc.AppendElement("BillOfMaterial")
    6. Dim AssemblyNode = BOMNode.AppendElement("AssemblyInformation")
    7. Dim ComponentsNode = AssemblyNode.AppendElement("Components")
    8. Dim CommissionNode = AssemblyNode.AppendElement("Commission")
    9. CommissionNode.AppendText(CStr(cINI.INI_ReadValueFromFile("ProjectInfo", "Commission", "", strProjectINI)))
    10. Dim ProjectNode = AssemblyNode.AppendElement("Project")
    11. ProjectNode.AppendText(CStr(cINI.INI_ReadValueFromFile("ProjectInfo", "Project", "", strProjectINI)))
    12. Dim CustomerNode = AssemblyNode.AppendElement("Customer")
    13. CustomerNode.AppendText(CStr(cINI.INI_ReadValueFromFile("ProjectInfo", "Customer", "", strProjectINI)))
    14. 'BOM Components-Information
    15. For i = 1 To oBomRows.Count
    16. Dim ComponentNode = ComponentsNode.AppendElement("Component")
    17. ComponentNode.AppendAttribute("DocId", CStr(oCompDefUseProps.Item("Dok-ID").Value))
    18. Dim ItemNumberNode = ComponentNode.AppendElement("ItemNumber")
    19. ItemNumberNode.AppendText(CStr(oBomRow.ItemNumber))
    20. 'oder noch kürzer:
    21. ComponentsNode.AppendElement("Quantity").AppendText(CStr(oBomRow.ItemQuantity))
    22. ComponentsNode.AppendElement("Revision").AppendText(CStr(oCompDefSumProps.Item("Revision Number").Value))
    23. Next
    24. 'Save the XML-Document
    25. xmlDoc.Save(strWorkspacePath & "\Stücklisten\XML\" & CStr(oUseProps.Item("Zeichnungsnummer").Value) & " - " & CStr(oRefDesProps.Item("Description").Value) & ".xml")
    26. End Sub
    Ich kanns leider nicht wirklich testen, weil ich dein cIni-Dingens nicht hab , und weitere Randbedungungen fehlen.
    Aber wenns läuft hast du nun einiges zu tun, dahinterzukommen, warum es läuft (und das ist das eiglich wichtige)

    Bei Fragen bitte fragen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    OK, ich habe mit deinem Beispiel etwas herumexperimentiert und mir das Ganze mal versucht zu verinnerlichen...
    Auch bin ich deinem Link gefolgt und habe noch etwas Google bemüht.

    ​Mit den Extension-Methods ist es also unteranderem möglich bestehenden Klassen eigene Methoden zu ergänzen, ohne dabei die eigentliche Klasse manipulieren zu müssen.
    ​Auch brauche ich so keine neue Klasse erstellen, welche von einer anderen Klasse erbt, nur um gewünschte Methoden ergänzen zu können.

    ​Das bedeutet, dass ich so wie du, einfach die XmlNode-Klasse um die gewünschten Methoden erweitere, mit dem Ziel die benötigten Funktionalitäten einmalig in einer Extension-Method zu definieren.
    ​Dies ist natürlich super praktisch und erspart einem genau das, was ich fabriziert habe... Nämlich endlose Code-Blöcke mit immer dem selben Schema, zur Erreichung eines eigentlich simplen Ziels.

    ​Ich werde deinen Code aufgreifen und noch etwas damit spielen, mit dem Ziel das ganze noch besser zu verstehen und in Zukunft auch Anwenden zu können.
    Genau da liegt nämlich oft mein Problem... Ich schreibe Code, welcher am Ende auch die gewünschte Aufgabe erfüllt und stelle dann fest, dass es viel elegantere, mir aber unbekannte Möglichkeiten zur Erreichung meiner Ziele gibt.

    Wenigstens habe ich heute wieder dazu gelernt ;)

    ​Ich danke dir auf jeden Fall für die Hilfe und komme gegebenenfalls mit Fragen zurück :)
    Als nächstes würde ich 2 Dinge angehen (eins nach dem anderen natürlich):
    1. Diese Props - Dinger (oCompDefSumProps, oUseProps,...) mal angucken
      Weil sowas: CStr(oCompDefSumProps.Item("Revision Number").Value) ist ja von ausgesuchter Hässlichkeit.
      Erste Frage wäre: Welchen Datentyp haben die?
      Dann gehts weiter, aber erstmal diese Frage beantworten. Wenn du Schwierigkeiten damit hast, vlt. hilft Video-Tut: Welchen Datentyp hat das Objekt?
      ...
    2. Den cINI - Kram rauswerfen.
      Das Ini-File-Format ist überholt, man verwendet heute Xml.
      Und wo du eh nun in Xml unterwegs bist, wärs doch unschlau, deine Ini nicht im Xml-Format zu halten. Weil da hampelst du ja mit 2 verschiedenen Technologien herum, die im Grunde beide dasselbe machen: String-Daten in eine Datei speichern und einlesen.

    Danke für die Tipps.

    Zu 1.
    Wie Eingangs schon gesagt handelt es sich bei dem ganzen um ein AddIn für eine vorhandene CAD-Software namens "Autodesk Inventor".
    Ist somit also leider kein Standalone... aus diesem Grund ist es leider auch zwecklos, wenn ich dir mein Projekt zur Verfügung stelle, damit du mal einen Blick drauf wirfst

    Bei diesen "Props-Dingern" handelt es sich um Schnittstellen zu den Eigenschaftswerten von Dokumenten des CAD-Programms.

    Bei CStr(oCompDefSumProps.Item("Revision Number").Value) handelt es sich bei dem ​Value um den Type Object...
    ​Dies liegt wohl daran, dass dies die Values der Eigenschaften aus der CAD-Software sind und diese Values verschiedene Typen wie ​Strings, ​Boolean, usw. enthalten können...

    ​Und durch ​Option Strict bin ich dazu gezwungen die ​Values vom Type ​Object mit Hilfe von ​cstr() in einen String zu konvertieren oder nicht?

    Auch hier bin ich für elegantere Methoden immer und gerne offen.

    Zu 2.
    Ja das mit den INI-Files stimmt wohl. Das war damals mein erstes Ergebnis, auf meiner Suche beliebige Werte auf einfachste Weise auch über das Programmende hinaus zu speichern.
    ​Ich hatte schonmal überlegt das auf XML umzustellen, habe es aber immer wieder hinten an gestellt.

    ​Zudem wollte ich mich bei Gelegenheit mal ausführlicher mit XML beschäftigen, da ich ja aktuell nur die aller primitivsten Basics kenne.

    Ruzbacky schrieb:

    Und durch Option Strict bin ich dazu gezwungen die Values vom Type Object mit Hilfe von cstr() in einen String zu konvertieren oder nicht?
    Ja, stimmt - gottlob!
    Aber ich kann eine Änderung der XmlDocumentX-Methoden vorschlagen - dann würde die Convertierung dort erledigt, und könnte dein UserCode noch weiter bisserl entlasten:

    VB.NET-Quellcode

    1. Imports System.Xml
    2. Imports System.Runtime.CompilerServices
    3. Public Module XmlDocumentX
    4. ''' <summary> Fügt ein XmlElement in xel ein, und returnt es </summary>
    5. <Extension()> _
    6. Public Function AppendElement(xel As XmlNode, tagName As String) As XmlElement
    7. AppendElement = xel.OwnerDocument.CreateElement(tagName)
    8. xel.AppendChild(AppendElement)
    9. End Function
    10. ''' <summary> Fügt einen Textnode in xel ein, returnt ihn aber
    11. nicht (weil man eh nix mit weiterverarbeiten kann) </summary>
    12. <Extension()> _
    13. Public Sub AppendText(xel As XmlNode, value As Object)
    14. xel.AppendChild(xel.OwnerDocument.CreateTextNode(value.ToString))
    15. End Sub
    16. ''' <summary> Fügt ein XmlAttribute in xel ein, returnt ihn
    17. aber nicht (weil man eh nix mit weiterverarbeiten kann) </summary>
    18. <Extension()> _
    19. Public Sub AppendAttribute(xel As XmlNode, attrName As String, value As Object)
    20. Dim attr = xel.OwnerDocument.CreateAttribute(attrName)
    21. attr.Value = value.ToString
    22. xel.Attributes.Append(attr)
    23. End Sub
    24. End Module

    Dann wäre so möglich:

    VB.NET-Quellcode

    1. 'BOM Components-Information
    2. For i = 1 To oBomRows.Count
    3. Dim ComponentNode = ComponentsNode.AppendElement("Component")
    4. ComponentNode.AppendAttribute("DocId", oCompDefUseProps.Item("Dok-ID").Value)
    5. 'probier auch mal so aus:
    6. ComponentNode.AppendAttribute("DocId", oCompDefUseProps("Dok-ID").Value)
    7. Dim ItemNumberNode = ComponentNode.AppendElement("ItemNumber")
    8. ItemNumberNode.AppendText(CStr(oBomRow.ItemNumber))
    9. 'oder noch kürzer:
    10. ComponentsNode.AppendElement("Quantity").AppendText(CStr(oBomRow.ItemQuantity))
    11. ComponentsNode.AppendElement("Revision").AppendText(oCompDefSumProps.Item("Revision Number").Value)
    12. 'probier auch mal so aus:
    13. ComponentsNode.AppendElement("Revision").AppendText(oCompDefSumProps("Revision Number").Value)
    14. Next

    Wenn zeilen #6 & #16 funktionieren, frag mich bitte, warum (oder sag es mir, wenndes schon weisst)



    Ach und mitte oBomRow ists ja ähnlich - ist das auch aussm CAD-Prog - oder welchen Datentyp hat das?
    Sooo... Ich habe mir heute Abend mal die letzten zwei Stunden Zeit genommen und alles durchgearbeitet, was du mir an Input zur Verfügung gestellt hast.
    Als erstes habe ich deine Extension-Methods abgeschrieben (Ja ich habe sie abgeschrieben, weil hätte ich sie nur kopiert und eingefügt, dann hätte ich morgen schon wieder vergessen wie die Extension-Methods funktionieren )

    VB.NET-Quellcode

    1. Imports System.Runtime.CompilerServices
    2. Imports System.Xml
    3. Public Module modExtensions
    4. <Extension()>
    5. Public Function AppendRootElement(ByVal xDoc As XmlDocument, ByVal strName As String) As XmlElement
    6. AppendRootElement = xDoc.CreateElement(strName)
    7. xDoc.AppendChild(AppendRootElement)
    8. End Function
    9. <Extension()>
    10. Public Function AppendElement(ByVal xNode As XmlNode, ByVal strName As String) As XmlElement
    11. AppendElement = xNode.OwnerDocument.CreateElement(strName)
    12. xNode.AppendChild(AppendElement)
    13. End Function
    14. <Extension()>
    15. Public Sub AppendText(ByVal xNode As XmlNode, ByVal value As Object)
    16. xNode.AppendChild(xNode.OwnerDocument.CreateTextNode(value.ToString))
    17. End Sub
    18. <Extension()>
    19. Public Sub AppendAttribute(ByVal xNode As XmlNode, ByVal attrName As String, ByVal value As Object)
    20. Dim attr As XmlAttribute = xNode.OwnerDocument.CreateAttribute(attrName)
    21. attr.Value = value.ToString
    22. xNode.Attributes.Append(attr)
    23. End Sub
    24. End Module

    Ich habe die Extension-Methods um eine Methode erweitert, da ich mit der Extension-Method AppendElement beim Erstellen der RootNode im XmlDocument eine NullReferenceExeption bekommen habe.
    Nach etwas Überlegen ist mir die Erleuchtung gekommen woran dies liegen mag. Da ich die RootNode dem XmlDocument direkt hinzufüge und nicht als AppendChild eines bestehenden XmlNodes, ist die RootNode ein AppendCild des XmlDocuments und nicht ein AppendChild eines XmlNodes.

    Dann habe ich meinen bestehenden Code mit den neuen Extension-Methods modifiziert und konnte somit extrem viele Codezeilen einsparen.
    Das ganze sieht nun in etwa so aus:

    VB.NET-Quellcode

    1. Dim xmlDoc As New XmlDocument
    2. Dim xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", Nothing)
    3. xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement)
    4. Dim BOMNode = xmlDoc.AppendRootElement("BillOfMaterial")
    5. Dim AssemblyNode = BOMNode.AppendElement("AssemblyInformation")
    6. Dim ComponentsNode = BOMNode.AppendElement("Components")
    7. Dim AssDescriptionNode = AssemblyNode.AppendElement("Description")
    8. AssDescriptionNode.AppendText(oRefDesProps("Description").Value)
    9. Dim DrawingNumberNode = AssemblyNode.AppendElement("DrawingNumber")
    10. DrawingNumberNode.AppendText(oUseProps("Zeichnungsnummer").Value)
    11. Dim DrwRevisionNode = AssemblyNode.AppendElement("RevisionNumber")
    12. DrwRevisionNode.AppendText(oSumProps("Revision Number").Value)
    13. Dim DrwAuthorNode = AssemblyNode.AppendElement("Author")
    14. DrwAuthorNode.AppendText(oRefSumProps("Author").Value)
    15. Dim DateNode = AssemblyNode.AppendElement("Date")
    16. DateNode.AppendText(DateTime.Today.ToString("dd.MM.yyyy"))

    Was leider nicht funktioniert ist, die beiden Extension-Methods in einer Zeile abzuarbeiten:

    VB.NET-Quellcode

    1. Dim AssDescriptionNode = AssemblyNode.AppendElement("Description").AppendText(oRefDesProps("Description").Value)

    Hier bekomme ich direkt die Meldung: Der Ausdruck ergibt keinen Wert

    Aber dafür konnte ich wie von dir vorgeschlagen das Wörtchen .Item überall weglassen.
    Meine Begründung dafür ist, dass es sich dabei um Arrays handelt und ich mit .Item nichts anderes mache als ein "Item" aus dem Array auszuwählen und zu verarbeiten.
    Das .Item kann man sich also sparen und das den gewünschten Wert des Arrays einfach direkt auswählen, indem man den gewünschten Wert einfach direkt in Klammen hinter das Array schreibt.


    Des Weiteren habe ich gelernt, dass ich bei der Deklaration den Typ weglassen kann, also aus

    VB.NET-Quellcode

    1. Dim AssemblyNode As XmlElement = ...
    wird einfach

    VB.NET-Quellcode

    1. Dim AssemblyNode = ...
    .
    Ich dachte immer bei Option Strict müssten Alle Variablen mit korrektem Datentyp deklariert werden.
    Das man den Datentyp weglassen kann und automatisch der korrekte Datentyp erkannt und genutzt wird hängt dann mit Option Infer zusammen oder?
    Bitte korrigiere mich überall wo ich falsch liege :)

    ​Meine INI-Files auszumustern und durch XML-Files zu ersetzten habe ich noch nicht erledigt, aber ich denke, dass ich dies auch noch in Angriff nehmen werde.

    ​Ich danke dir auf jeden Fall für die super Hilfestellungen und das neu erlangte Wissen :)

    Ruzbacky schrieb:

    Sooo... Ich habe mir heute Abend mal die letzten zwei Stunden Zeit genommen und alles durchgearbeitet, was du mir an Input zur Verfügung gestellt hast.
    Als erstes habe ich deine Extension-Methods abgeschrieben (Ja ich habe sie abgeschrieben, weil hätte ich sie nur kopiert und eingefügt, dann hätte ich morgen schon wieder vergessen wie die Extension-Methods funktionieren )

    VB.NET-Quellcode

    1. Imports System.Runtime.CompilerServices
    2. Imports System.Xml
    3. Public Module modExtensions
    4. <Extension()>
    5. Public Function AppendRootElement(ByVal xDoc As XmlDocument, ByVal strName As String) As XmlElement
    6. AppendRootElement = xDoc.CreateElement(strName)
    7. xDoc.AppendChild(AppendRootElement)
    8. End Function
    9. <Extension()>
    10. Public Function AppendElement(ByVal xNode As XmlNode, ByVal strName As String) As XmlElement
    11. AppendElement = xNode.OwnerDocument.CreateElement(strName)
    12. xNode.AppendChild(AppendElement)
    13. End Function
    14. <Extension()>
    15. Public Sub AppendText(ByVal xNode As XmlNode, ByVal value As Object)
    16. xNode.AppendChild(xNode.OwnerDocument.CreateTextNode(value.ToString))
    17. End Sub
    18. <Extension()>
    19. Public Sub AppendAttribute(ByVal xNode As XmlNode, ByVal attrName As String, ByVal value As Object)
    20. Dim attr As XmlAttribute = xNode.OwnerDocument.CreateAttribute(attrName)
    21. attr.Value = value.ToString
    22. xNode.Attributes.Append(attr)
    23. End Sub
    24. End Module

    Ich habe die Extension-Methods um eine Methode erweitert, da ich mit der Extension-Method AppendElement beim Erstellen der RootNode im XmlDocument eine NullReferenceExeption bekommen habe.
    Jo - so ist das, wenn ich nicht selbst testen kann.
    Deine Überlegungen dazu scheint mir halbrichtig, v.a. gibts bei einer NullReferenceException eiglich garnix zu überlegen.
    Sondern man muss was tun, nämlich herausfinden, welches Objekt Nothing ist (und nicht sein darf).
    Siehe auch Exceptions, und was sie uns sagen wollen
    In diesem Fall kanns kaum was anderes sein, was Nothing ist als in

    VB.NET-Quellcode

    1. AppendElement = xNode.OwnerDocument.CreateElement(strName)
    der TeilAusdruck

    VB.NET-Quellcode

    1. xNode.OwnerDocument
    Das wäre jdfs. logisch: Wenn xNode das Document selbst ist, dann ist höchst plausibel, dass dieser XmlNode kein .OwnerDocument hat (weil er isses ja selber).
    Das Problem lässt sich also auch durch eine kleine Änderung in .AppendElement() fixen:

    VB.NET-Quellcode

    1. Imports System.Xml
    2. Imports System.Runtime.CompilerServices
    3. Public Module XmlDocumentX
    4. ''' <summary> Fügt ein XmlElement in xnd ein, und returnt es </summary>
    5. <Extension()> _
    6. Public Function AppendElement(xnd As XmlNode, tagName As String) As XmlElement
    7. Dim xDoc = If(xnd.OwnerDocument, DirectCast(xnd, XmlDocument)) ' wenn xnd kein OwnerDocument hat, isses das selber
    8. AppendElement = xDoc.CreateElement(tagName)
    9. xnd.AppendChild(AppendElement)
    10. End Function
    11. ''' <summary> Fügt einen Textnode in xnd ein, returnt ihn aber nicht (weil man eh nix mit weiterverarbeiten kann) </summary>
    12. <Extension()> _
    13. Public Sub AppendText(xnd As XmlNode, value As Object)
    14. Dim xDoc = If(xnd.OwnerDocument, DirectCast(xnd, XmlDocument))
    15. xnd.AppendChild(xDoc.CreateTextNode(value.ToString))
    16. End Sub
    17. ''' <summary> Fügt ein XmlAttribute in xnd ein, returnt ihn aber nicht (weil man eh nix mit weiterverarbeiten kann) </summary>
    18. <Extension()> _
    19. Public Sub AppendAttribute(xnd As XmlNode, attrName As String, value As Object)
    20. Dim xDoc = If(xnd.OwnerDocument, DirectCast(xnd, XmlDocument))
    21. Dim attr = xDoc.CreateAttribute(attrName)
    22. attr.Value = value.ToString
    23. xnd.Attributes.Append(attr)
    24. End Sub
    25. End Module
    Und die diesbezügliche Abfrage auch in die anneren beiden Methoden einbauen.
    Auch wenn das deine Lösung gleich wieder ad acta zu legen geeignet ist (und dir gleich die nächste Recherche aufbürdet: If-Operator, (especial with 2 Arguments)), bleibt dennoch die Hauptsache, dass du Extension-Methods verstanden hast, und selbst welche schreiben kannst. :thumbsup:



    Ruzbacky schrieb:


    Was leider nicht funktioniert ist, die beiden Extension-Methods in einer Zeile abzuarbeiten:

    VB.NET-Quellcode

    1. Dim AssDescriptionNode = AssemblyNode.AppendElement("Description").AppendText(oRefDesProps("Description").Value)

    Hier bekomme ich direkt die Meldung: Der Ausdruck ergibt keinen Wert
    Jo, is logisch, dass das nicht funktioniert (dassis letztlich fast immer logisch):
    .AppendElement() ist eine Function, die gibt etwas zurück, nämlich das appendete Element. Und das hat welchen Datentyp? XmlElement.
    Daher kann man an diesen Rückgabewert gleich die nächste Append-Methode dranhängen.
    .AppendText() appendet aber kein XmlElement, sondern einen - guck nach, mit dem Tut aus post#8 - XmlText - Objekt.
    In ein XmlText-Objekt kann man nichts weiter hineinschachteln, deshalb habich die Methode .AppendText() garnet als Function designed, sondern als Sub - ohne Rückgabewert (wie gesagt: was es zurückgeben könnte, damit kann man nix anfangen).
    Jo, das sagt der Fehler: "Der Ausdruck ergibt keinen Wert". (Und weil das keinen Wert ergibt, kanns auch nicht auf der rechten Seite einer Zuweisung stehen - logisch oder?)



    Ruzbacky schrieb:

    Aber dafür konnte ich wie von dir vorgeschlagen das Wörtchen .Item überall weglassen.
    Meine Begründung dafür ist, dass es sich dabei um Arrays handelt...
    Nein, Arrays indiziert man mit Zahlen - sowas: oRefDesProps("Description")würde mit einem Array niemals gehen.
    Das Geheimnis heisst "Indexer", bzw. in vb.net: "DefaultProperty" - siehe auf Schlüsselworte das Schlüsselwort "Default" nach.
    Ist inhaltlich gut erklärt, nur diese Bemerkung: "..., but they can make your code more difficult to read...." ist offensichtlich Blödsinn, oder findest du deinen Code dadurch schwerer lesbar? (ich finde das Gegenteil ist der Fall)
    Also umgekehrt wird ein Schuh draus: Nicht weil du .Item weglassen kannst ist das ein Array, sondern auch bei Array kann man das .Item weglassen, weil Array hat auch sone Default-Property - sogar desselben Namens (allerdings für numerische Indexe, nicht für Strings).



    Ruzbacky schrieb:

    Das man den Datentyp weglassen kann und automatisch der korrekte Datentyp erkannt und genutzt wird hängt dann mit Option Infer zusammen oder?
    :thumbsup:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    ErfinderDesRades schrieb:

    Jo, is logisch, dass das nicht funktioniert (dassis letztlich fast immer logisch):
    .AppendElement() ist eine Function, die gibt etwas zurück, nämlich das appendete Element. Und das hat welchen Datentyp? XmlElement.
    Daher kann man an diesen Rückgabewert gleich die nächste Append-Methode dranhängen.
    .AppendText() appendet aber kein XmlElement, sondern einen - guck nach, mit dem Tut aus post#8 - XmlText - Objekt.
    In ein XmlText-Objekt kann man nichts weiter hineinschachteln, deshalb habich die Methode .AppendText() garnet als Function designed, sondern als Sub - ohne Rückgabewert (wie gesagt: was es zurückgeben könnte, damit kann man nix anfangen).
    Jo, das sagt der Fehler: "Der Ausdruck ergibt keinen Wert". (Und weil das keinen Wert ergibt, kanns auch nicht auf der rechten Seite einer Zuweisung stehen - logisch oder?)


    Soo, nachdem ich meine Arbeitswoche nun auch erfolgreich beendet habe und die Zeit gefunden habe mich mit dem ganzen noch etwas auseinanderzusetzten...

    Wenn du es so erklärst leuchtet es ein, warum dies so nicht möglich ist wie ich es mir vorgestellt habe.

    Der If-Operator mit zwei Argumenten ist ja eigentlich eine echt praktische Sache um genau mein Problem der NullReferenceExeption zu umschiffen. Leider war mir diese Funktionsweise des If-Operators bis dato völlig unbekannt.
    Bedeutet also, dass wenn der If-Operator mit zwei Argumenten sinnvoll eingesetzt wird, um eine NullReferenceExeption vermeidet, da er zunächst auf das erste Argument zurückgreift und im Fall, dass dieses Nothing liefert, er alternativ einfach auf das zweite Argument zurückgreift.
    Bleibt die Frage was passiert wenn beide Argumente Nothing liefern? Naja ist ja ein leichtes dies zu testen, wobei die Antwort wohl eindeutig sein dürfte... Wenn beides Nothing ist, wird es wohl wieder auf die NullReferenceExeption hinaus laufen.


    Das mit dem Default-Property kommt mir in der Tat nicht unbekannt vor... Ich glaube das in meinem VB.NET Buch bereits gelesen zu haben.
    Da lag ich mit meiner Array Theorie wohl daneben, habe aber somit gelernt, dass die Indizes von Arrays immer nummerisch angesprochen werden.


    Dann werde ich mich dieses Wochenende mal wieder etwas mit meinem Code beschäftigen und wahrscheinlich auch die alten INI-Files durch XMLs ersetzten :)