Warm tip: This article is reproduced from stackoverflow.com, please click
vb.net xml

Change attributes in nested XML

发布于 2020-04-07 10:16:36

I have an XML file with nested elements/nodes. I need to increment the <proceduralStep> attribute "id" for each node and its child nodes. My first problem is I haven't been able to make changes to the attribute using node.Attributes("id").Value = node.Attributes("id").Value + 1. It gives an error on the node.Attributes("id").Value +1. This is the parent element /proceduralStep/. Second problem is I need each nodes attribute to be changed if it's a child element of <proceduralStep>. So if it's /proceduralStep/proceduralStep that attributes id will be changed to 1.1. I've been searching the net for examples and explanations on how to do this but haven't found any that work.

Sample XML

<dmodule>
  <mainProcedure>
    <proceduralStep id="step1">
      <para>Step 1</para>
    </proceduralStep>
    <proceduralStep id="step2">
      <figure id="fig2">
        <title>xxxxx</title>
        <graphic infoEntityIdent="ICN-GAASI"></graphic>
      </figure>
    </proceduralStep>
    <proceduralStep id="step3">
      <para>Step 3 with link to step 2 (ID 23) here:
                <internalRef internalRefId="step2" internalRefTargetType="step"></internalRef></para>
      <figure id="fig3">
        <title>xxxxx</title>
        <graphic infoEntityIdent="ICN-GAASIB0"></graphic>
      </figure>
      <proceduralStep id="step3.1">
        <para>Step 3.2 with link to step 3.1 (ID 23a) here:
                    <internalRef internalRefId="step3.1" internalRefTargetType="step"></internalRef></para>
      </proceduralStep>
      <proceduralStep id="step3.2">
        <figure>
          <title>xxxxx</title>
          <graphic infoEntityIdent="ICN-GAASIB0-00-"></graphic>
        </figure>
        <proceduralStep id="step3.2.1">
          <figure>Step 3.3.1</figure>
        </proceduralStep>
        <proceduralStep id="step3.2.2">
          <para>Step 3.3.2 with link to step 3.3.1 (ID 23c1) here:
                        <internalRef internalRefId="step3.2.1" internalRefTargetType="step"></internalRef></para>
        </proceduralStep>
        <proceduralStep id="step3.2.3">
          <figure>Step 3.3.3</figure>
        </proceduralStep>
      </proceduralStep>
    </proceduralStep>
  </mainProcedure>
</dmodule>

Not working code


        Dim doc As XDocument = XDocument.Load(FILENAME)
        Dim directoryName As String = Path.GetDirectoryName(FILENAME)
        Dim root As XElement = doc.Root
        Dim prefixStep As String = "step"
        Dim prefixFig As String = "fig"
        Dim nameResult As String = Path.GetFileName(FILENAME)
        Dim ns As XNamespace = root.GetDefaultNamespace()
        Dim mainProcedure As XElement = root.Descendants("mainProcedure").FirstOrDefault()

        RenumberStep(mainProcedure, prefixStep, ns)
        RenumberFigures(mainProcedure, prefixFig, ns)

        For Each internalRef As XElement In doc.Descendants(ns + "internalRef")
        Dim oldId As String = CType(internalRef.Attribute("internalRefId"), String)
            If Not oldId Is Nothing Then
                If dictionary.ContainsKey(oldId) Then
                    internalRef.SetAttributeValue("internalRefId", dictionary(oldId))
                Else
                    '  internalRef.SetAttributeValue("internalRefId", "Error : " & oldId)
                End If
            End If
        Next internalRef

        doc.Save(FILENAME)
Module Module1
    Public dictionary As New Dictionary(Of String, String)
    Public dictionaryFig As New Dictionary(Of String, String)

    Sub RenumberStep(parent As XElement, prefix As String, ns As XNamespace)
        Dim index As Integer = 1
        For Each proceduralStep As XElement In parent.Elements(ns + "proceduralStep")
            Dim oldId = CType(proceduralStep.Attribute("id"), String)
            If Not oldId Is Nothing Then
                dictionary.Add(oldId, prefix + index.ToString())
                proceduralStep.SetAttributeValue("id", prefix + index.ToString())
                RenumberStep(proceduralStep, prefix + index.ToString() + ".", ns)
            Else
                proceduralStep.SetAttributeValue("id", prefix + index.ToString())
            End If
            index = index + 1
        Next proceduralStep
    End Sub

    Sub RenumberFigures(parent As XElement, prefix As String, ns As XNamespace)
        Dim index As Integer = 1

        For Each figure As XElement In parent.Elements(ns + "figure")
            Dim oldfigId = CType(figure.Attribute("id"), String)
            If Not oldfigId Is Nothing Then
                dictionaryFig.Add(oldfigId, prefix + index.ToString())
                figure.SetAttributeValue("id", prefix + index.ToString())
                RenumberFigures(figure, prefix + index.ToString() + ".", ns)
            Else
                figure.SetAttributeValue("id", prefix + index.ToString())
            End If
            index = index + 1
        Next figure
    End Sub
End Module
Questioner
JenPann
Viewed
81
jdweng 2020-02-11 04:02

Real simple using a recursive algorithm and xml linq :

Module Module1
    Const FILENAME As String = "c:\temp\test.xml"
    Const OUTPUT_FILENAME As String = "c:\temp\test1.xml"

    Public dictionary As New Dictionary(Of String, String)
    Sub Main()
        Dim doc As XDocument = XDocument.Load(FILENAME)
        Dim root As XElement = doc.Root
        Dim ns As XNamespace = root.GetDefaultNamespace()
        Dim mainProcedure As XElement = root.Descendants("mainProcedure").FirstOrDefault()
        Dim prefix As String = "step"
        Renumber(mainProcedure, prefix, ns)

        For Each internalRef As XElement In doc.Descendants(ns + "acronymTerm")
            Dim oldId As String = CType(internalRef.Attribute("internalRefId"), String)
            If Not oldId Is Nothing Then

                If dictionary.ContainsKey(oldId) Then
                    internalRef.SetAttributeValue("internalRefId", dictionary(oldId))
                Else
                    internalRef.SetAttributeValue("internalRefId", "Error : " & oldId)
                End If
            End If
        Next internalRef

        doc.Save(OUTPUT_FILENAME)
    End Sub

    Sub Renumber(parent As XElement, prefix As String, ns As XNamespace)
        Dim index As Integer = 1
        For Each proceduralStep As XElement In parent.Elements(ns + "proceduralStep")
            Dim oldId = CType(proceduralStep.Attribute("id"), String)
            dictionary.Add(oldId, prefix + index.ToString())
            proceduralStep.SetAttributeValue("id", prefix + index.ToString())

            Renumber(proceduralStep, prefix + index.ToString() + ".", ns)
            index = index + 1
        Next proceduralStep
    End Sub

End Module

Output

<?xml version="1.0" encoding="utf-8"?>
<dmodule xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.s1000d.org/S1000D_4-0-1/xml_schema_flat/proced.xsd">
  <mainProcedure>
    <proceduralStep id="step1">
      <para>XX  xxx<acronym id="mosim">XX  xxx<acronymTerm>XX  xxx</acronymTerm>XX  xxx<acronymDefinition>XX  xxx</acronymDefinition>XX  xxx</acronym>XX  xxx<internalRef internalRefId="Error : Error : fig1" internalRefTargetType="figure" targetTitle="fig1">XX  xxx</internalRef>XX  xxx</para>
      <proceduralStep id="step1.1">
        <para>XX  xxx</para>
      </proceduralStep>
      <proceduralStep id="step1.2">
        <para>XX  xxx<acronymTerm internalRefId="mosim">XX  xxx</acronymTerm>XX  xxx</para>
      </proceduralStep>
      <proceduralStep id="step1.3">
        <para>XX  xxx</para>
      </proceduralStep>
    </proceduralStep>
    <proceduralStep id="step2">
      <para>XX  xxx<acronymTerm internalRefId="mosim">XX  xxx</acronymTerm>XX  xxx<internalRef internalRefId="Error : Error : fig1" internalRefTargetType="figure" targetTitle="fig1">XX  xxx</internalRef>XX  xxx</para>
      <proceduralStep id="step2.1">
        <para>XX  xxx<acronymTerm internalRefId="mosim">XX  xxx</acronymTerm>XX  xxx</para>
      </proceduralStep>
      <proceduralStep id="step2.2">
        <para>XX  xxx<acronymTerm internalRefId="mosim">XX  xxx</acronymTerm>XX  xxx</para>
      </proceduralStep>
    </proceduralStep>
    <proceduralStep id="step3">
      <para>XX  xxx<emphasis>XX  xxx</emphasis>XX  xxx</para>
    </proceduralStep>
    <proceduralStep id="step4">
      <para>XX  xxx<emphasis>XX  xxx</emphasis>XX  xxx</para>
    </proceduralStep>
    <proceduralStep id="step5">
      <para>XX  xxx<acronymTerm internalRefId="lola">XX  xxx</acronymTerm>XX  xxx<acronym id="cd">XX  xxx<acronymTerm>XX  xxx</acronymTerm>XX  xxx<acronymDefinition>XX  xxx</acronymDefinition>XX  xxx</acronym>XX  xxx<acronymTerm internalRefId="mosim">XX  xxx</acronymTerm>XX  xxx<acronymTerm internalRefId="cd">XX  xxx</acronymTerm>XX  xxx<acronym id="dvd">XX  xxx<acronymTerm>XX  xxx</acronymTerm>XX  xxx<acronymDefinition>XX  xxx</acronymDefinition>XX  xxx</acronym>XX  xxx</para>
    </proceduralStep>
  </mainProcedure>
</dmodule>