patpower
patpower

Reputation: 1

Rename a page in onenote with VBA, unable to apply changes, cannot save xml

I would like to copy a page from my template section and rename it. For now, I merge sections because I only have one page in the template section. So I need to rename the page in the new section but I m not able to make it works! It changes the name in the code but not able to get it applied to the document.

Here the code that I use with declaration followed the part just after merging those sections:

'Microsoft OneNote 15.0 Object Library
'Microsoft XML, 5.0 (comes from 6.0 originally but a lot of code not working on 6.0)

Private Sub CommandButton5_Click()

 Dim onenote As onenote.Application
 Set onenote = New onenote.Application
 Dim MypageName as string
 MypageName = "page title"

' Get the XML that represents the OneNote sections
    Dim oneNoteSectionsXml As String

    onenote.GetHierarchy "", 4, oneNoteSectionsXml

    Dim doc As MSXML2.DOMDocument
    Set doc = New MSXML2.DOMDocument

    If doc.LoadXML(oneNoteSectionsXml) Then
        Dim nodeNoteBooks As MSXML2.IXMLDOMNodeList
        Dim nodeSections As MSXML2.IXMLDOMNodeList
        Dim nodepages As MSXML2.IXMLDOMNodeList
        
        
        Set nodeNoteBooks = doc.DocumentElement.SelectNodes("//one:Notebook")
        Set nodeSections = doc.DocumentElement.SelectNodes("//one:Section")
        Set nodepages = doc.DocumentElement.SelectNodes("//one:Page")
         
        
        Dim nodeNoteBook As MSXML2.IXMLDOMNode
        Dim nodeSection As MSXML2.IXMLDOMNode
        Dim nodePage As MSXML2.IXMLDOMNode
`For Each nodePage In nodepages
   If nodePage.Attributes.getNamedItem("name").Text = nodeSections.item(2).ChildNodes(0).Attributes.getNamedItem("name").Text Then nodePage.Attributes.getNamedItem("name").Text = MypageName
       
       onenote.UpdateHierarchy doc.XML
       doc.Save doc.XML
 next

end if

end sub      `

UpdateHierarchy gives no error but no results and doc.save gives an error (wrong parameters).

Is it the right way to do it ?

I tried a lot of solutions all around but nothing works. The original code was copied and it was on microsoft xml 6.0 but a lot of error came out so I tried to adapt it for 5.0 and its working, exept for this part.

Thanks for help!

Upvotes: 0

Views: 217

Answers (2)

MT1
MT1

Reputation: 984

Here is the code I used to rename a page in OneNote.

The name of a page in OneNote is part of the page content, pages are uniquely identified by their GUID.

I used the following code to get a list of page GUIDs (known as ID to OneNote).

This makes it simpler to illustrate here as pages can then be retrieved by their GUID.

I have several pages with the same name so if the same applies to you then it may be worth alphabetising the pages before changing their names.

OneNote also allows a blank page name.

Sub sbGetPagesXML()
    Dim oneNote As oneNote.Application
    Set oneNote = New oneNote.Application
    Dim sPagesXML As String
    oneNote.GetHierarchy "", hsPages, sPagesXML, xs2013
    'MsgBox sPagesXML
    sbPrint (sPagesXML)
End Sub
Sub sbPrint(sText As String): Open "C:\tmp\z-" & Format(Now(), "HHMMSS") & ".txt" For Output As #1: Print #1, sText: Close #1: End Sub

I then used this code to retrieve a specific page XML to check when the page has be renamed.

Sub sbGetPageContent()
    Dim oneNote As oneNote.Application
    Set oneNote = New oneNote.Application
    Dim sPageContentXML As String
    oneNote.GetPageContent "{9D710DD4-704A-4F0C-B2E0-54153AA5EB42}{1}{E195 ... your GUID here }", sPageContentXML, piAll, xs2013
    'MsgBox sPageContentXML
    sbPrint (sPageContentXML)
End Sub

The following is the simple procedure to rename a page.

Option Explicit

Sub sbUpdatePageContent()
    
    Dim oneNote As oneNote.Application
    Set oneNote = New oneNote.Application
    Dim sPageContentXML As String
    Dim PgRenDoc As MSXML2.DOMDocument60
    Set PgRenDoc = New MSXML2.DOMDocument60
    oneNote.GetPageContent "{9D710DD4-704A-4F0C-B2E0-54153AA5EB42}{1}{E195 ... your GUID here }", sPageContentXML, piAll, xs2013

    ' Load Page's XML into a MSXML2.DOMDocument object.
    PgRenDoc.LoadXML (sPageContentXML)

    ' Find the Title element.
    Dim titleNode As MSXML2.IXMLDOMNode
    PgRenDoc.SetProperty "SelectionNamespaces", "xmlns:one='http://schemas.microsoft.com/office/onenote/2013/onenote'"
    Set titleNode = PgRenDoc.SelectSingleNode("//one:Page/one:Title/one:OE/one:T")

    ' Get the CDataSection where OneNote stores the Title text.
    Dim cdataChild As MSXML2.IXMLDOMNode
    Set cdataChild = titleNode.SelectSingleNode("text()")

    ' Change the title in the local XML copy.
    cdataChild.Text = "This page was renamed - " & Format(Now(), "YYYYMMDD HH:MM ")
    ' Write the update to OneNote.
    oneNote.UpdatePageContent PgRenDoc.XML
    
End Sub

Then use sbGetPageContent to check the XML and OneNote displays the changed page name.

Notes.

I do not have XML 5.0 available on my Windows 11 computer, only XML 3.0 and XML 6.0. The DOMDocument should be referred to as MSXML2.DOMDocument60 The references I used were as follows,

Visual Basic For Applications

Microsoft Excel 16.0 Object Library

OLE Automation

Microsoft Office 16.0 Object Library

Microsoft XML, v6.0

Microsoft Visual Basic for Applications Extensibility 5.3

Microsoft OneNote 15.0 Object Library

and the code I used to list the references was -

Sub Grab_References()
    'Comments:
    '
    'Purpose: List all references used in the workbook
    'Additional information: http://www.cpearson.com/Excel/vbe.aspx
    '
    'References: Microsoft Visual Basic for Applications Extensibility 5.3
    '
    'Date       Developer       Action
    '---------------------------------------------
    '01/18/12   ws              Created

    Dim wb As Workbook
    Dim ws As Worksheet
    Dim n As Integer
    Dim x As Integer

    Set wb = ThisWorkbook
    Set ws = wb.Worksheets("Sheet1")
    
    With wb
        On Error Resume Next
        x = 1
        For n = 1 To .VBProject.References.Count
            ws.Cells(x, 1) = n
            ws.Cells(x, 2) = .VBProject.References.Item(n).Description
            ws.Cells(x, 3) = .VBProject.References.Item(n).Major
            ws.Cells(x, 4) = .VBProject.References.Item(n).Minor
            ws.Cells(x, 5) = .VBProject.References.Item(n).FullPath
            ws.Cells(x, 6) = .VBProject.References.Item(n).GUID
            x = x + 1
        Next n
        ws.Columns("A:G").EntireColumn.AutoFit
    End With
    
    'Tidy up
        Set wb = Nothing
        Set ws = Nothing
End Sub

The version of OneNote I used was "Microsoft® OneNote® for Microsoft 365 MSO (Version 2405 Build 16.0.17628.20006) 64-bit" Apparently there is a pre-installed version of OneNote which comes with Windows known as "OneNote for Windows 10". I uninstalled it to make sure I knew what version I was using.

My OneNote is not synced to OneDrive, pages are saved to the local computer only. The default directory is "C:\Users\david\Documents\OneNote Notebooks"

I used fragments of many of the examples of OneNote VBA code from SO and MS Support. Not many of them worked for the following reasons.

The namespace must be xs2013 in the .GetPageContent call or the call returns nothing with no message and this counts as success, obviously. This is despite the version of OneNote installed on my computer being "Build 16...".

To use the abbreviation "one:Notebook", for example, the following property must be set on the XML object before using SelectNodes

Dim doc As MSXML2.DOMDocument60
doc.SetProperty "SelectionNamespaces", "xmlns:one='http://schemas.microsoft.com/office/onenote/2013/onenote'" ' set this property before using SelectNodes

This property must also refer to the namespace 2013.

The VBA code is run from Excel and may not work if OneNote is open when the code runs. The error is likely to be "Automation Error".

Upvotes: 0

patpower
patpower

Reputation: 1

I finally get it working. I think that I must reload another xml with page content.

Here the entire code if it could help someone! It merge the template section (ongletNameOrigine) (index of the start section) with the destination section (ongletNameDestination) (index of destination section), then it loop through the destination section to find the template page by its name TemplatePageName (I only have one page in template section) and rename it with the right name (MypageName). Its not optimized but you can use it to get started!

Private Sub CommandButton5_Click()

'Make sure to add the references to:
'Microsoft OneNote 15.0 Object Library
'Microsoft XML, 5.0

'ref to: https://github.com/pierrms/Alphabetize-OneNote-Sections-VBA/blob/master/OneNote_Sort_VBA.bas

Unload Me
    Dim notebookSortName As String
    Dim ongletNameOrigine As Integer
    Dim ongletNameDestination As Integer
    Dim MypageName As String
    Dim contrat As String
    Dim item As String
    Dim Mac As String
    Dim TemplatePageName As String
    Dim templatePageID As String
    
'Templates = 2, Projets en cours =3, Projets en appro =4, Projets terminés =5

'set section value
    contrat = Cells(ActiveCell.Row, 1).Value
    item = Cells(ActiveCell.Row, 2).Value
    notebookSortName = "11A-Famille Expert C1SCAN"
    ongletNameOrigine = 2: ongletNameDestination = 3
    Mac = Application.InputBox("numero machine (911-912-913-871)")
    MypageName = "PL-" + contrat + "-" + item + " (" + Mac + ")"
    TemplatePageName = "PL-Contrat-Item (871,911,912,913)"


    Dim onenote As onenote.Application
    Set onenote = New onenote.Application

' Get the XML that represents the OneNote sections
    Dim oneNoteSectionsXml As String
    
    onenote.GetHierarchy "", 4, oneNoteSectionsXml


    Dim doc As MSXML2.DOMDocument
    Set doc = New MSXML2.DOMDocument

    If doc.LoadXML(oneNoteSectionsXml) Then
        Dim nodeNoteBooks As MSXML2.IXMLDOMNodeList
        Dim nodeSections As MSXML2.IXMLDOMNodeList
        Dim nodepages As MSXML2.IXMLDOMNodeList
        
        Set nodeNoteBooks = doc.DocumentElement.SelectNodes("//one:Notebook")
        Set nodeSections = doc.DocumentElement.SelectNodes("//one:Section")
        Set nodepages = doc.DocumentElement.SelectNodes("//one:Page")
      
        Dim nodeNoteBook As MSXML2.IXMLDOMNode
        Dim nodeSection As MSXML2.IXMLDOMNode
        Dim nodepage As MSXML2.IXMLDOMNode
        Dim sectionIDXML As String
        Dim section2IDXML As String
               
        Dim pageXML As String
        Dim updatedPageXML As String
        Dim pageID As String
        
      'VÉRIFICATION DES ONGLETS
          If nodeSections.item(ongletNameDestination).Attributes.getNamedItem("name").Text <> "Projets en cours" Then MsgBox "onglet de destination erroné, supposé être Projets en cours mais  " & nodeSections.item(ongletNameDestination).Attributes.getNamedItem("name").Text: Exit Sub
          If nodeSections.item(ongletNameOrigine).Attributes.getNamedItem("name").Text <> "Templates" Then MsgBox "onglet de destination erroné, supposé être Templates mais  " & nodeSections.item(ongletNameOrigine).Attributes.getNamedItem("name").Text: Exit Sub
       'vérif template page name
          If nodeSections.item(ongletNameOrigine).ChildNodes(0).Attributes.getNamedItem("name").Text <> TemplatePageName Then MsgBox "nom de page de template incorrect, devrait être  " + TemplatePageName + "  mais est: " + nodeSections.item(ongletNameOrigine).ChildNodes(0).Attributes.getNamedItem("name").Text: Exit Sub
       
       'check if good notebook
        If nodeSections.item(ongletNameDestination).ParentNode.Attributes.getNamedItem("name").Text <> notebookSortName Then MsgBox "mauvais notebook, supposé être  " & notebookSortName & "  mais " & nodeSections.item(ongletNameDestination).ParentNode.Attributes.getNamedItem("name").Text: Exit Sub
        If nodeSections.item(ongletNameOrigine).ParentNode.Attributes.getNamedItem("name").Text <> notebookSortName Then MsgBox "mauvais notebook, supposé être  " & notebookSortName & "  mais " & nodeSections.item(ongletNameOrigine).ParentNode.Attributes.getNamedItem("name").Text: Exit Sub
       
  
       sectionIDXML = nodeSections.item(ongletNameOrigine).Attributes.getNamedItem("ID").Text
       section2IDXML = nodeSections.item(ongletNameDestination).Attributes.getNamedItem("ID").Text
    
       onenote.MergeSections sectionIDXML, section2IDXML
    
      onenote.GetHierarchy "", 4, oneNoteSectionsXml
      Set doc = New MSXML2.DOMDocument
      If doc.LoadXML(oneNoteSectionsXml) Then Set nodeSections = doc.DocumentElement.SelectNodes("//one:Section")

     'onglet destination, rename template page
      If nodeSections.item(ongletNameDestination).ChildNodes.Length > 0 Then
         For x = 1 To nodeSections.item(ongletNameDestination).ChildNodes.Length
              If nodeSections.item(ongletNameDestination).ChildNodes(x).Attributes.getNamedItem("name").Text = TemplatePageName Then
             
                     pageID = nodeSections.item(ongletNameDestination).ChildNodes(x).Attributes.getNamedItem("ID").Text
                     onenote.GetPageContent pageID, pageXML, 0
            
                     doc.LoadXML pageXML
                     doc.SelectSingleNode("//one:Page/one:Title/one:OE/one:T").Text = MypageName
                     updatedPageXML = doc.XML
                     'objShell.Popup updatedPageXML
                     onenote.UpdatePageContent updatedPageXML
                     onenote.UpdateHierarchy updatedPageXML
                     Exit For
               End If
         Next
      End If

               
 End If

End Sub

Upvotes: 0

Related Questions