0

i have an xml in this format:

    ?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <Products>
      <Categoria nome="etichetta">
        <riga1>val1</riga1>
        <riga2>val2</riga2>
        <riga3>val3</riga3>
      </Categoria>
      <Categoria nome="etichetta2">
        <riga1>val1</riga1>
        <riga2>val2</riga2>
        <riga3>val3</riga3>
      </Categoria>
..... and so on.....
    </Products>

so i want to change the value "etichetta"

Private Sub modifica_nome(nuovo_nome As String)
    Dim Percorso As String = "//Products/Categoria[@nome='" & Combo_Etichetta.SelectedItem & "']"
    Dim node = doc.SelectSingleNode(Percorso)
    node.Value = nuovo_nome 'here i get error. 
    doc.Save(file_etichette)
end sub

program, load the xml into a combobox:

doc.Load(file_etichette) 
        Combo_Etichetta.Items.AddRange(doc.DocumentElement.SelectNodes("Categoria").Cast(Of XmlNode).Select(Function(x) x.Attributes("nome").Value).ToArray)

then i load data into textbox on combobox.selectedindexchanged

    Dim Percorso As String = "//Products/Categoria[@nome='" & Combo_Etichetta.SelectedItem & "']"
    
T_scatole_CODICE_1.Text = doc.DocumentElement.SelectSingleNode(Percorso & "/riga1").InnerText
T_scatole_QTA_1.Text = doc.DocumentElement.SelectSingleNode(Percorso & "/riga2").InnerText
T_scatole_POS_1.Text = doc.DocumentElement.SelectSingleNode(Percorso & "/riga3").InnerText

the "@nome=" value is linked to a product after that i let user to select the data trought combobox, visualize the data and let the user to modify if needed from default values, to print a label. it, happens that "@nome=" value need to be changed to a new model product, so i need to change that.

FOUD THE SOLUTION by myself: the error is that node.vale expect some data in tag "categoria" but nome="rtichetta" isn't a tag but a parameter, so must use node.Attributes("nome").Value

Dim Percorso As String = "//Products/Categoria[@nome='" & Combo_Etichetta.SelectedItem & "']"
Dim node = doc.SelectSingleNode(Percorso)
node.Attributes("nome").Value = nuovo_nome
doc.Save(file_etichette)
1
  • Can you show us a sample value of nuevo_nome and then the resulting XML you want? As you selected the Categoria element with SelectSingleNode I thought you want to change that element's content, but perhaps you want to select or change only the nome attribute value. Commented Jul 24, 2021 at 16:54

2 Answers 2

1

Creating classes, and using XML serialization, can make it easier to work with XML-especially if you are both reading and updating the XML.

To start, first look at the structure of the XML.

- Products
    -Categoria
        -riga1
        -riga2
        -riga3

We'll create a class for "Products" and also for "Categoria".

  • Products: contains "Categoria"
  • ProductsCategoria: contains attributes for "Categoria", as well as "riga1", "riga2", "riga3"

Create a class (name: ProductsCategoria.vb)

ProductsCategoria.vb

Imports System.Xml.Serialization

<XmlType(TypeName:="Categoria")>
Public Class ProductsCategoria
    <XmlAttribute(AttributeName:="nome")>
    Public Property Nome As String

    <XmlElement(ElementName:="riga1")>
    Public Property riga1 As String

    <XmlElement(ElementName:="riga2")>
    Public Property riga2 As String

    <XmlElement(ElementName:="riga3")>
    Public Property riga3 As String

    Sub New()

    End Sub

    Sub New(nome As String, riga1 As String, riga2 As String, riga3 As String)
        'set values
        Me.Nome = nome
        Me.riga1 = riga1
        Me.riga2 = riga2
        Me.riga3 = riga3
    End Sub
End Class

There wasn't enough data supplied in the OP to know if "Products" may contain more than one "Categoria", but from the name "Products" being the plural form of "Product", it gives indication that it may contain more than one "Categoria". Therefore, we'll use a List of "Categoria" (ProductsCategoria). "riga1", "riga2", and "riga3" are all unique names, so they won't use a List.

Create a class (name: Products.vb)

Products:

Imports System.Xml.Serialization


<XmlRoot(ElementName:="Products")>
Public Class Products

    <XmlElement(ElementName:="Categoria")>
    Public Categorias As New List(Of ProductsCategoria)

End Class

Next, we'll write our code to both read the XML from file (deserialize) and write the XML to file (serialize).

Create a module (name: HelperXml.vb)

HelperXml.vb

Module HelperXml

    Public Function DeserializeXMLFileToObject(Of T)(xmlFilename As String) As T
        'usage
        'Dim myClass1 As Class1 = DeserializeXMLFileToObject(Class1)(xmlFilename)

        Dim rObject As T = CType(Nothing, T)

        Try
            If String.IsNullOrEmpty(xmlFilename) Then
                Return rObject
            End If

            Using xmlStream As System.IO.StreamReader = New System.IO.StreamReader(xmlFilename)
                'create new instance
                Dim serializer As System.Xml.Serialization.XmlSerializer = New System.Xml.Serialization.XmlSerializer(GetType(T))

                'read XML from file
                rObject = CType(serializer.Deserialize(xmlStream), T)
            End Using
        Catch ex As Exception
            Debug.WriteLine("Error (DeserializeXMLFileToObject) - " & ex.Message)
            Throw ex
        End Try

        Return rObject
    End Function

    Public Sub SerializeObjectToXMLFile(obj As Object, xmlFilename As String)
        'Usage:
        'Dim myClass1 As Class1 = New Class1()
        'SerializeObjectToXMLFile(myClass1, xmlFilename)

        Try
            If String.IsNullOrEmpty(xmlFilename) Then
                Return
            End If

            Dim settings As System.Xml.XmlWriterSettings = New System.Xml.XmlWriterSettings()
            settings.Encoding = System.Text.Encoding.UTF8
            settings.OmitXmlDeclaration = False
            settings.Indent = True

            Using xmlWriter As System.Xml.XmlWriter = System.Xml.XmlWriter.Create(xmlFilename, settings)
                'specify namespaces
                Dim ns As System.Xml.Serialization.XmlSerializerNamespaces = New System.Xml.Serialization.XmlSerializerNamespaces()
                ns.Add(String.Empty, "urn:none")

                xmlWriter.WriteProcessingInstruction("xml", "version=""1.0"" encoding=""UTF-8"" standalone=""yes""")

                'create new instance
                Dim serializer As System.Xml.Serialization.XmlSerializer = New System.Xml.Serialization.XmlSerializer(obj.GetType())

                'write XML to file
                serializer.Serialize(xmlWriter, obj, ns)

            End Using

        Catch ex As Exception
            Debug.WriteLine("Error (SerializeObjectToXMLFile) - " & ex.Message)
            Throw ex
        End Try
    End Sub
End Module

Usage:

Private prods As New Products
Private xmlFilename As String = New String("C:\Temp\test_products.xml")
                   ...

Private Sub ChangeName(index As Integer, name As String)
    If prods IsNot Nothing AndAlso prods.Categorias.Count > 0 AndAlso index >= 0 AndAlso index < prods.Categorias.Count Then
        prods.Categorias(index).Nome = name

        'Write to file
        SerializeObjectToXMLFile(prods, xmlFilename)
    End If
End Sub

Private Sub ReadXmlFromFile()
    prods = HelperXml.DeserializeXMLFileToObject(Of Products)(xmlFilename)
End Sub

Private Sub WriteXmlToFile()
    prods.Categorias.Add(New ProductsCategoria("etichetta", "val1", "val2", "val3"))
    SerializeObjectToXMLFile(prods, xmlFilename)
End Sub

Resources:

Sign up to request clarification or add additional context in comments.

1 Comment

The code above will work with the updated XML file.
0
Dim Percorso As String = "//Products/Categoria[@nome='" & Combo_Etichetta.SelectedItem & "']"
Dim node = doc.SelectSingleNode(Percorso)
node.Attributes("nome").Value = nuovo_nome

can be shortened to

Dim Percorso As String = "//Products/Categoria/@nome[. = '" & Combo_Etichetta.SelectedItem & "']"
Dim node = doc.SelectSingleNode(Percorso)
node.Value = nuovo_nome

2 Comments

don't work, it's the same error i made at the beginning.
@DarkAngel00, your original code selected the element node, this suggestion selects the attribute node. And for an attribute node you can set the Value property.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.