2017-03-10 3 views
1

Dies ist mein erster Beitrag hier. Tausend Dank, dass Sie mich um sich haben und es tut mir leid, wenn ich bei diesem ersten Versuch Fehler mache oder Missverständnisse erzeuge. Mein Rätsel ist wie folgt: ich ein kleines Skript geschrieben, einige Drittanbieter-Software-Komponenten für die Aktualisierung, die erfordert, Ändern eine XML-Datei mit der folgenden Struktur:Hinzufügen eines Elements zu einem XML-Dokument mit einer zuvor neu erstellten Zeichenfolge von einem Attributknoten

<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <PropertyGroup> 
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> 
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform> 
    <ProductVersion> 
    </ProductVersion> 
    <SchemaVersion>2.0</SchemaVersion> 
    <ProjectGuid>xxx</ProjectGuid> 
    <OutputType>xxx</OutputType> 
    <StartupObject>xxx</StartupObject> 
    <RootNamespace>xxx</RootNamespace> 
    <AssemblyName>xxx</AssemblyName> 
    <FileAlignment>xxx</FileAlignment> 
    <MyType>WindowsFormsWithCustomSubMain</MyType> 
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> 
    <TargetFrameworkProfile> 
    </TargetFrameworkProfile> 
    <SccProjectName>xxx</SccProjectName> 
    <SccLocalPath>xxx</SccLocalPath> 
    <SccAuxPath>xxx</SccAuxPath> 
    <SccProvider>xxx</SccProvider> 
    </PropertyGroup> 
    <PropertyGroup> 
... 
<ItemGroup> 
    <Reference Include="someString, Version=123, Culture=neutral, PublicKeyToken=ab1, processorArchitecture=xxx"> 
     <SpecificVersion>False</SpecificVersion> 
     <Private>True</Private> 
    </Reference> 

Die fraglichen Funktion einen Teil aus dem Attribute nimmt umfassen und sollte idealerweise zu einem neu erstellten XML-Element hinzugefügt werden (zB <HintPath>xyz</HintPath>). Das Auswählen des Attributs und das Abrufen der Zeichenfolge funktionierte, sobald ich das Namespace-Problem umgehen konnte (dank StackOverflow). Wenn ich jedoch das HintPath-Element mithilfe von AppendChild hinzufüge, erhalte ich die Fehlermeldung, dass das Objekt nicht korrekt referenziert wird. Ich habe versucht, LINQ zu verwenden, um das Problem zu beheben, konnte jedoch die Abfrage Syntax nicht umgehen (da ich gewohnt bin, XPath zu verwenden). Wenn jemand eine LINQ-Lösung hat, lassen Sie es mich wissen.

Dies ist mein Code so weit (XPath-Ansatz)

Private Function getAttributInclude(ByVal path2xml As String) As List(Of String) 
     Dim xmlDoc As XmlDocument = New XmlDocument() 
     Dim listAttributValues As New List(Of String) 
     Dim nodeAttributInsertValueSplitted() As String 
     Dim splittedStringMitEndungDll As String 
     Dim nsmanager As XmlNamespaceManager = New XmlNamespaceManager(xmlDoc.NameTable) 
     nsmanager.AddNamespace("msn", "http://schemas.microsoft.com/developer/msbuild/2003") 
     nsmanager.AddNamespace(String.Empty, "urn:test") 'default namespace 

     xmlDoc.Load(path2xml) 


     Dim nodeListAttributInclude As XmlNodeList 
     Dim root As XmlElement = xmlDoc.DocumentElement 
     nodeListAttributInclude = root.SelectNodes("/Project/ItemGroup/Reference/@Include") 
     Dim nodeAttributeInclude As XmlNode 
     Dim hintPath As XmlElement 
     For Each nodeAttributeInclude In nodeListAttributInclude 
      nodeAttributInsertValueSplitted = nodeAttributeInclude.Value.Split(",") 
      splittedStringMitEndungDll = String.Format("..\..\lib\{0}.dll", nodeAttributInsertValueSplitted(0)) 
      listAttributValues.Add(nodeAttributeInclude.InnerText) 
      hintPath = xmlDoc.CreateElement("HintPath", nodeAttributeInclude.NamespaceURI) 
      hintPath.InnerText = splittedStringMitEndungDll 
      nodeAttributeInclude.ParentNode.AppendChild(hintPath) 
     Next 
     xmlDoc.Save(path2xml) 

     Return listAttributValues 

ich besonders gefragt, warum .AppendChild ist in diesem Fall nicht

Dank mil im Voraus für jede Hilfe zur Verfügung gestellt zu arbeiten.

Dear all

würde Genau wie Sie ein Update geben. Ich kam zurück zu dem Projekt und bekam einen guten Ansatz. Es stellte sich jedoch heraus, dass dies nur ein Schritt in die richtige Richtung war, und ich könnte dafür verantwortlich sein, dass ich nicht explizit geschrieben habe, was ich mit dem Original beabsichtigte. Der neue Code-Schnipsel ist wie folgt: Dim xDoc Wie XDocument = XDocument.Load (path2xml)

Dim nsmanager As New XmlNamespaceManager(New NameTable) 

    nsmanager.AddNamespace("ns", "http://schemas.microsoft.com/developer/msbuild/2003") 
    nsmanager.AddNamespace(String.Empty, "urn:test") 'default namespace 

    Dim ns As XNamespace = "http://schemas.microsoft.com/developer/msbuild/2003" 

    Dim xAttr = xDoc.XPathSelectElement("//ns:Reference", nsmanager).Attribute("Include").Value 

    Dim hpElement As New XElement(New XElement(ns + "HintPath", xAttr)) 

    xDoc.XPathSelectElement("//ns:Reference", nsmanager).Add(hpElement) 

    xDoc.Save(path2xml) 

Bisher das XML-Element entsprechend erstellt wird. Mit dem Xpath-Ausdruck dachte ich, dass ich alle Elemente mit dem gesuchten Attribut bekommen würde. Außerdem hätte ich am Anfang gerne eine Nodeliste erhalten, da ich für jeden Knoten/jedes Element, der das Attribut enthält, Ersatz für die Attribut-Zeichenkette anwenden würde. Es stellte sich heraus, dass nur das erste Element mit Ihrem Vorschlag ausgewählt wurde. Hier sind meine neuen Fragen: 1. Ist es möglich, alle Knoten mit dieser Syntax auszuwählen? 2. Wie würde ich die String-Ersetzung (n) in jedem Attributknoten ausführen? Bitte beziehen Sie sich auf meinen ursprünglichen Beitrag, indem Sie meine ursprüngliche Idee anhand einer Knotenliste und Iteration über jeden Knoten für die Ersetzungen zeigen. aber ich konnte das XML-HintPath-Element am Ende nicht erstellen). Ich glaube, ich wurde auf dem Weg aufgrund meiner fehlenden Programmiererfahrung verwirrt, tut mir leid, dass Wäre großartig, wenn Sie oder jemand anderes mehr Licht auf dieses Thema werfen könnte.

Update: Ich hatte ein anderer auf den Code gehen, und es gibt eine Sache, die ich nicht verstehe überhaupt: jede Zeile in dem Codeblock oben erneut geprüft haben, ich auf die folgende Zeile kam:

xDoc.XPathSelectElement("//ns:Reference", nsmanager).Add(hpElement) 

Die Beschreibung der Parameter und Rückgabewerte besagt, dass ein einzelner Wert retrended würde. Ich gebe zu, dass ich diese speziellen Informationen vorher nicht gelesen habe. Ich sah jedoch, dass eine Pluralversion, d. H. XPathSelectElements, ebenfalls möglich war. Nach meinem Verständnis schien das ein guter Ansatz (und ein leichter, aber allzu typischer Tippfehler).Zu meiner großen Überraschung beim Wechsel der Linie

xDoc.XPathSelectElements("//ns:Reference", nsmanager).Add(hpElement) 

bekam ich eine Fehlermeldung, dass

Attribute is not a member of System.Collection.Generic.IEnumerable(Of System.Xml.Linq.XElement 

Das ist genau das, was ich nicht verstehe. Wie kann die Auswahl aller Elemente falsch sein? Und wie ist es möglich, eine Liste aller durch den XPAth Expression ausgewählten Knoten zur weiteren Verarbeitung zu bekommen? Ich bin jetzt ziemlich ratlos. Ich freue mich auf Ihre Antworten.

Ich versuchte die folgenden Ansätze in diesem und anderen Foren gefunden.

Dim xAttr = xDoc.XPathSelectElement("//ns:Reference", nsmanager).Attribute("Include").Value 

Dim xAttr = xDoc.Root.Descendants("Reference").Attributes("Include") 

Dim xAttr = xDoc.XPathEvaluate("//Reference/@Include") 

Allerdings scheint keiner dieser Ansätze zu funktionieren. Ich kann die Attribut-Zeichenfolge nicht auswählen und die Ersetzungen entsprechend ausführen. Vielleicht hilft das bei der Identifizierung des Problems.

Update: Ich habe einen anderen Blick auf meinen vorherigen Code und war in der Lage, einige Probleme zu lösen (siehe Code unten). Ich kann jetzt alle Knoten auswählen, die ich mir vorgestellt habe. Außerdem scheinen im Debug-Modus auch die Ersetzungen anzustoßen. Allerdings, und das fängt an, mich zu ärgern, ich kann nicht herausfinden, wie man das Neue mit einigen der ersetzten Saiten hinzufügt. Das Beispiel von Microsoft

uses XmlNode root = doc.DocumentElement; 

Was Ich mag würde uns tun aacomplish den bereits vorhandenen XPath-Ausdruck für das Element verwendet wird. Während ich versuche, bekomme ich normalerweise einen Fehler, dass das Objekt 'x' nicht in Objekt 'y' umgewandelt werden kann. Könnte mir bitte jemand helfen, dieses Problem zu lösen?

Dies ist der neue Code

Private Function getAttributInclude(ByVal pfad2xml As String) As XmlDocument 

Dim xDoc As New XmlDocument 
xDoc.Load(pfad2xml) 

Dim ns As XNamespace = "http://schemas.microsoft.com/developer/msbuild/2003" 

Dim nsmanager As New XmlNamespaceManager(New NameTable) 

nsmanager.AddNamespace("ns", "http://schemas.microsoft.com/developer/msbuild/2003") 
nsmanager.AddNamespace(String.Empty, "urn:test") 

Dim navigator As XPathNavigator = xDoc.CreateNavigator() 

Dim xpathAttributInclude As XPathExpression = XPathExpression.Compile("//ns:Reference/ns:SpecificVersion/../@Include") 

xpathAttributInclude.SetContext(nsmanager) 

Dim xpathElementSpecificVersion As XPathExpression = XPathExpression.Compile("//ns:Reference/ns:SpecificVersion") 
xpathElementSpecificVersion.SetContext(nsmanager) 

Dim nodeListAttributInclude As XPathNodeIterator = navigator.Select(xpathAttributInclude) 
Dim nodeListElementSpecificVersion As XPathNodeIterator = navigator.Select(xpathElementSpecificVersion) 

Dim hintPath As XmlElement 

For Each nodeAttributInclude In nodeListAttributInclude 
    Dim nodeAttributInsertValueSplitted = nodeAttributInclude.Value.Split(",") 
    Dim replacedNodeText As String 
    Dim splittedStringMitEndungDll 
    Dim replacedVersionAttribut As String 

    replacedNodeText = nodeAttributInsertValueSplitted(0).ToString.Replace(_ 
     txtBoxEnterVersionNummerOld.Text, txtBoxEnterVersionNummerNew.Text) 

    writeLog(replacedNodeText + vbCrLf) 

    splittedStringMitEndungDll = String.Format("..\..\lib\{0}.dll", replacedNodeText) 

    writeLog(splittedStringMitEndungDll + vbCrLf) 

    If tbXmlDevExpressVersionNew.Text.Length > 0 Then 
     Dim splittedElementSpecificVersion = nodeAttributInsertValueSplitted(1).Split("=") 

     replacedVersionAttribut = splittedElementSpecificVersion(1).ToString.Replace(_ 
       splittedElementSpecificVersion(1).ToString, tbXmlDevExpressVersionNew.Text) 

     writeLog(replacedVersionAttribut + vbCrLf) 
    Else 
      MessageBox.Show("Please enter a valid version numbers") 
    End If 

    hintPath = xDoc.CreateElement("HintPath", nodeAttributInclude.NamespaceURI) 
    hintPath.InnerText = splittedStringMitEndungDll 

    Dim node2insertAfter = xDoc.DocumentElement 

    For Each nodeElementSpecificVersion In nodeListElementSpecificVersion 
     xDoc.InsertAfter(hintPath, node2insertAfter.SelectSingleNode("//Reference/SpecificVersion")) 
     writeLog(nodeElementSpecificVersion.ToString + vbCrLf) 
    Next 

Next 

xDoc.Save("c:\tmp\result_xml.xml") 

Return xDoc 
End Function 

Update: ich auf eine interesting article kam, dass man Streptokokken auf eine Lösung zur Verfügung gestellt. Allerdings habe ich immer noch das Problem, dass das betreffende Element nur an das letzte Element angehängt wird, obwohl ich eine Schleife in einer Schleife verwende. Außerdem scheint der Ersatz nicht zu greifen. Hier ist ein Ausschnitt aus dem angepassten appendChild Abschnitt zum Hinzufügen der XML-Elemente

For Each nodeElementReference In nodeListElementReference 
       Dim node2StartInsert = DirectCast(nodeElementReference, System.Xml.IHasXmlNode).GetNode 
       node2StartInsert.AppendChild(hintPath) 
      Next 

Dank einer mil im Voraus für Ihre assisstance.

Mit freundlichen Grüßen Sas

ich eine Lösung finden verwaltet. Der Code muss jedoch nur zum Extrahieren des Attributs verwendet werden, das jetzt korrekt in der XML-Eingabedatei enthalten ist, auf die dieser Code angewendet wird. Die Verwendung von XMLElement und XPathNavigator bot die Möglichkeit, das zusätzliche Element in die vorhandene XML-Datei zu schreiben.

Dim hintPath As XmlElement 
    Dim nodeAttributInclude As XPathNavigator 

    For Each nodeAttributInclude In nodeListAttributInclude 
     Dim nodeAttributInsertValueSplitted = nodeAttributInclude.Value.Split(",") 


     Dim versionsInfoText As String 
     Dim splittedStringMitEndungDll 


     versionsInfoText = nodeAttributInsertValueSplitted(0).ToString 


     splittedStringMitEndungDll = String.Format("..\..\lib\{0}.dll", versionsInfoText) 


     nodeAttributInclude.MoveToParent() 


     hintPath = xDoc.CreateElement("HintPath") 
     hintPath.InnerText = splittedStringMitEndungDll 


     nodeAttributInclude.AppendChild("<HintPath>" + hintPath.InnerText + "</HintPath>") 
    Next 

    xDoc.Save("c:\tmp\result_xml.xml") 
+0

Update: Ich habe einige Kontrollen und fand heraus, dass die XPath Notationen erscheinen nicht ausgewertet werden. Ich habe den relativen und absoluten Pfad Notation versucht. Die Auswahl von nur // @ Include führte jedoch wie erwartet zu einer Nodelist.Ich bin mir nicht sicher, aber ich nehme an, dass die XPath-Implementierung möglicherweise kaputt ist. Wäre großartig, wenn jemand eine Erklärung hinzufügen könnte. – Sasquatch

+0

Jemand wies darauf hin, dass nicht klar war, welches Dokument meine Quell- und Zieldatei war. Die Eingabedatei ist der hier veröffentlichte XML-Code. Die Ausgabedatei soll identisch sein, aber das zusätzliche XML-Element muss hinzugefügt werden ( sollte daher ein anderes untergeordnetes Element mit dem Namen erhalten, das wiederum die geänderte Teilzeichenfolge enthält). Ich hoffe, das hilft für weitere Diskussionen – Sasquatch

+0

Um genauer zu sein über den Fehler. Das Problem ist, dass "System.Xml.XmlNodeList" nicht in "System.Xml.XmlNode" konvertiert werden kann. Die Frage ist, wie ich zu den Knoten gelangen soll, die für das Finden der korrekten Position für InsertAfter benötigt werden, wenn keine Knotenliste verwendet wird. Ich dachte auch, dass die Schleife dafür sorgen würde. Ich bin jetzt ziemlich verwirrt und ratlos. – Sasquatch

Antwort

0

Ich habe es geschafft, eine Lösung zu finden. Der Code muss jedoch nur zum Extrahieren des Attributs verwendet werden, das jetzt korrekt in der XML-Eingabedatei enthalten ist, auf die dieser Code angewendet wird. Die Verwendung von XMLElement und XPathNavigator bot die Möglichkeit, das zusätzliche Element in die vorhandene XML-Datei zu schreiben. Dim HintPath Wie XmlElement Dim nodeAttributInclude Als XPathNavigator

For Each nodeAttributInclude In nodeListAttributInclude 
    Dim nodeAttributInsertValueSplitted = nodeAttributInclude.Value.Split(",") 


    Dim versionsInfoText As String 
    Dim splittedStringMitEndungDll 


    versionsInfoText = nodeAttributInsertValueSplitted(0).ToString 


    splittedStringMitEndungDll = String.Format("..\..\lib\{0}.dll", versionsInfoText) 


    nodeAttributInclude.MoveToParent() 


    hintPath = xDoc.CreateElement("HintPath") 
    hintPath.InnerText = splittedStringMitEndungDll 


    nodeAttributInclude.AppendChild("<HintPath>" + hintPath.InnerText + "</HintPath>") 
Next 

xDoc.Save("c:\tmp\result_xml.xml") 
Verwandte Themen