Microsoft Office Forums

Go Back   Microsoft Office Forums > >

Reply
 
Thread Tools Display Modes
  #1  
Old 06-06-2017, 06:51 AM
slaycock slaycock is offline Problem adding a namespace for customxml Windows 7 64bit Problem adding a namespace for customxml Office 2013
Expert
Problem adding a namespace for customxml
 
Join Date: Sep 2013
Posts: 255
slaycock is on a distinguished road
Default Problem adding a namespace for customxml

I'm trying to create a namespace in athe Custom XML part of a Word document.

I've done extensive googling but good documentation is thin to non-existent.

The following code is extracted from Microsoft's help pages on CustomXMLPrefixMappings

Code:
Sub addXMLNamespaceTest()

' https://msdn.microsoft.com/en-us/library/office/ff863518.aspx
Dim objNamespace As CustomXMLPrefixMapping
 
    objNamespace = CustomXMLPrefixMappings.AddNamespace(Prefix:="xs", NamespaceURI:="urn:invoice:namespace")
End Sub
but this gives a runtime error of object required and I can't figure out why.

A similar example found under the 'addnamespace' help (You have to add the XML to the CustomXMLPrefixMappings

https://msdn.microsoft.com/en-us/lib...ffice.15).aspx

Code:
Sub AddNamespacePrefix()
  
    Dim objCustomPrefixMappings As CustomXMLPrefixMappings
    Dim varCustomMapping As Variant
 
    ' Adds a custom namespace.
    varCustomMapping = objCustomPrefixMappings.AddNamespace("xs", "urn:invoice:namespace")
 
End Sub
Highlights the addNamespace term with the error 'Function or variable required'.



Can anyone assist with the correct syntax for adding a namespace.

If it helps I've tried the code below (with reference to https://www.w3schools.com/xml/xml_namespaces.asp )

and the xml parts are added under (no namespace) (1) and (no namespace (2) hence the investigation of .addNamsespace.

Code:
Sub testxmladd()

    ActiveDocument.CustomXMLParts.add XML:= _
        "<RCDP xmlns:a=""https://www.w3schools.com/furniture"">" & _
        "<a:arcprop id=""HeadingVisibilityP"">" & _
        "<a:visibility>True</a:visibility>" & _
        "<a:enabled>True</a:enabled>" & _
        "</a:arcprop>" & _
        "<a:arcprop id= ""HeadingVisibilityS"">" & _
        "<a:visibility>False</a:visibility>" & _
        "<a:checked>True></a:checked>" & _
        "</a:arcprop>" & _
        "</RCDP>"
    ActiveDocument.CustomXMLParts.add XML:= _
        "<RCDP xmlns:a=""https://www.w3schools.com/furniture"">" & _
        "<a:arcprop id=""HeadingVisibilityA"">" & _
        "<a:visibility>True</a:visibility>" & _
        "<a:enabled>True</a:enabled>" & _
        "</a:arcprop>" & _
        "<a:arcprop id= ""HeadingVisibilityR"">" & _
        "<a:visibility>False</a:visibility>" & _
        "<a:checked>True></a:checked>" & _
        "</a:arcprop>" & _
        "</RCDP>"

End Sub
Reply With Quote
  #2  
Old 06-07-2017, 03:49 AM
slaycock slaycock is offline Problem adding a namespace for customxml Windows 7 64bit Problem adding a namespace for customxml Office 2013
Expert
Problem adding a namespace for customxml
 
Join Date: Sep 2013
Posts: 255
slaycock is on a distinguished road
Default

I watched this excellent video on reading xml values from CustomXMLParts

http://ericwhite.com/blog/screen-cas...sing-word-vba/

I copied the code from the video to have a play around but I get an error where the author of the video doesnt

Code:
Sub xmlreadexample()

Dim sNS         As String
Dim sNSCustom   As String
Dim sNSPrefix   As String

Dim part        As CustomXMLParts
Dim parts       As CustomXMLParts


Dim nodes       As CustomXMLNodes
Dim node        As CustomXMLNode

    Set parts = ThisDocument.CustomXMLParts
    
    sNSCustom = "http://example.com/arc"

    For Each part In parts
        sNS = part.NamespaceURI
        If Len(sNS) = 0 Then
            Set nodes = part.SelectNodes("/arcRoot/arcProperties")
            If nodes.count > 0 Then
                For Each node In nodes
                    Debug.Print "NodeValue     = " & node.NodeValue
                    Debug.Print "NodeText      = " & node.Text
                    Debug.Print "Attribute no  = " & node.Attributes.count
                    For i = 1 To node.Attributes.count
                        Debug.Print "    Attrib name    = " & node.Attributes.Item(i).BaseName
                        Debug.Print "    Attrib value   = " & node.Attributes.Item(i).Text
                    Next i
                Next node
            End If
        Else
            If StrComp(sNS, sNSCustom, vbTextCompare) - 0 Then
                sNSPrefix = part.NamespaceManager.LookupPrefix(sNS)
                Set nodes = part.SelectNodes("/" & sNSPrefix & ":" & "arcRoot/arcProperties")
                If nodes.count > 0 Then
                    For Each node In nodes
                        Debug.Print "NodeValue     = " & node.NodeValue
                        Debug.Print "NodeText      = " & node.Text
                        Debug.Print "Attribute no  = " & node.Attributes.count
                        For i = 1 To node.Attributes.count
                            Debug.Print "    Attrib name    = " & node.Attributes.Item(i).BaseName
                            Debug.Print "    Attrib value   = " & node.Attributes.Item(i).Text
                        Next i
                    Next node
                End If
            End If
        End If
    Next
                    
            
End Sub
The error is a the line

sNS = part.NamespaceURI

and the error is 'Method or data member not found'

This CustomXMLPart stuff does seem to be fraught with multiple issues.

Can anyone shed any light on the above.

The only XML reference I have selected is MicrosoftXML v6.0
Reply With Quote
  #3  
Old 06-07-2017, 04:02 AM
slaycock slaycock is offline Problem adding a namespace for customxml Windows 7 64bit Problem adding a namespace for customxml Office 2013
Expert
Problem adding a namespace for customxml
 
Join Date: Sep 2013
Posts: 255
slaycock is on a distinguished road
Default

Looks like rubberducking has worked again

the error I made is here

Code:
Dim part        As CustomXMLParts
Dim parts       As CustomXMLParts
it should be

Code:
Dim part        As CustomXMLPart
Dim parts       As CustomXMLParts
Reply With Quote
  #4  
Old 06-07-2017, 03:30 PM
gmaxey gmaxey is offline Problem adding a namespace for customxml Windows 7 32bit Problem adding a namespace for customxml Office 2016
Expert
 
Join Date: May 2010
Location: Brasstown, NC
Posts: 1,589
gmaxey is a jewel in the roughgmaxey is a jewel in the roughgmaxey is a jewel in the roughgmaxey is a jewel in the rough
Default

Both of the parts you added already have a namespace but they were prefixed namespaces:

Code:
Sub testxmladd()
Dim i As Long
  For i = ActiveDocument.CustomXMLParts.Count To 4 Step -1
     ActiveDocument.CustomXMLParts(i).Delete
  Next
  'Add a part with Prefixed namespace:
  ActiveDocument.CustomXMLParts.Add XML:= _
        "<RCDP xmlns:a=""https://www.w3schools.com/furniture"">" & _
        "<a:arcprop id=""HeadingVisibilityP"">" & _
        "<a:visibility>True</a:visibility>" & _
        "<a:enabled>True</a:enabled>" & _
        "</a:arcprop>" & _
        "<a:arcprop id= ""HeadingVisibilityS"">" & _
        "<a:visibility>False</a:visibility>" & _
        "<a:checked>True></a:checked>" & _
        "</a:arcprop>" & _
        "</RCDP>"
  'Add a part with unprefixed namespace.
  ActiveDocument.CustomXMLParts.Add XML:= _
        "<RCDP xmlns=""https://www.w3schools.com/furniture"">" & _
        "<arcprop id=""HeadingVisibilityA"">" & _
        "<visibility>True</visibility>" & _
        "<enabled>True</enabled>" & _
        "</arcprop>" & _
        "<arcprop id= ""HeadingVisibilityR"">" & _
        "<visibility>False</visibility>" & _
        "<checked>True></checked>" & _
        "</arcprop>" & _
        "</RCDP>"
  MsgBox ActiveDocument.CustomXMLParts(4).NamespaceURI
  MsgBox ActiveDocument.CustomXMLParts(5).NamespaceURI
  MsgBox ActiveDocument.CustomXMLParts(4).NamespaceManager.Item(1).NamespaceURI
  MsgBox ActiveDocument.CustomXMLParts(5).NamespaceManager.Item(1).NamespaceURI
End Sub
__________________
Greg Maxey
Please visit my web site at http://www.gregmaxey.com/
Reply With Quote
  #5  
Old 06-08-2017, 12:39 AM
slaycock slaycock is offline Problem adding a namespace for customxml Windows 7 64bit Problem adding a namespace for customxml Office 2013
Expert
Problem adding a namespace for customxml
 
Join Date: Sep 2013
Posts: 255
slaycock is on a distinguished road
Default

Thanks for taking the time to look at the code and provide an example.

Unfortunately there are possibly still anomalies.

If I step through the code you kindly provided whilst watching what happens to the list of customXMLParts as seen from the XMLMappingPane (In the Developer Mapping Tab) you can see that the user defined namespaces are deleted. BUT

RCDP xmlns:a=""https://www.w3schools.com/furniture"" produces a namespace of (no namespace)

and

RCDP xmlns=""https://www.w3schools.com/furniture"" produces a namespace of https://www.w3schools.com/furniture


In the MsgBox statements

MsgBox ActiveDocument.CustomXMLParts(4).NamespaceURI
MsgBox ActiveDocument.CustomXMLParts(5).NamespaceURI

produce output of

Nothing
https://www.w3schools.com/furniture

whereas the last two msgbox statements produce

https://www.w3schools.com/furniture
https://www.w3schools.com/furniture

If I change the URI to furniture1 and furniture2 the same pattern persists.

In the XMP Mapping Pane

Furniture1 gives a namespace of (no namespace)
Furniture2 give a namespace of /www.w3schools.com/furniture2

The four Msgbox statements give output of

Nothing
https://www.w3schools.com/furniture2
https://www.w3schools.com/furniture1
https://www.w3schools.com/furniture2

This actually leaves me quite happy. The environment in which my code will be used its extremely unlikely there will be someone else using the same namespace and consequently I don't think I need to define a prefix (although that would be the more robust case).

But it would be useful to understand why we get (no namespace) when defining a prefix.

Also, I still can't find a way of making CustomXMLPrefixMappings.AddNamespace compile let alone test how it works.
Reply With Quote
  #6  
Old 06-08-2017, 03:37 AM
gmaxey gmaxey is offline Problem adding a namespace for customxml Windows 7 32bit Problem adding a namespace for customxml Office 2016
Expert
 
Join Date: May 2010
Location: Brasstown, NC
Posts: 1,589
gmaxey is a jewel in the roughgmaxey is a jewel in the roughgmaxey is a jewel in the roughgmaxey is a jewel in the rough
Default

What you are seeing is normal and to be expected. Consider this:

Code:
Sub testxmladd()
Dim i As Long
  For i = ActiveDocument.CustomXMLParts.Count To 4 Step -1
     ActiveDocument.CustomXMLParts(i).Delete
  Next
  'Add a part with Prefixed namespace:
  ActiveDocument.CustomXMLParts.Add XML:= _
        "<RCDP xmlns:a=""AAAAA"">" & _
        "<a:arcprop id=""HeadingVisibilityP"">" & _
        "<a:visibility>True</a:visibility>" & _
        "<a:enabled>True</a:enabled>" & _
        "</a:arcprop>" & _
        "<a:arcprop id= ""HeadingVisibilityS"">" & _
        "<a:visibility>False</a:visibility>" & _
        "<a:checked>True></a:checked>" & _
        "</a:arcprop>" & _
        "</RCDP>"
  'Add a part with default namespace (not prefixed).
  ActiveDocument.CustomXMLParts.Add XML:= _
        "<RCDP xmlns=""BBBBBBB"">" & _
        "<arcprop id=""HeadingVisibilityA"">" & _
        "<visibility>True</visibility>" & _
        "<enabled>True</enabled>" & _
        "</arcprop>" & _
        "<arcprop id= ""HeadingVisibilityR"">" & _
        "<visibility>False</visibility>" & _
        "<checked>True></checked>" & _
        "</arcprop>" & _
        "</RCDP>"
   ActiveDocument.CustomXMLParts.Add XML:= _
        "<RCDP xmlns=""CCCCCCCC"" xmlns:a=""DDDDDDDDD"">" & _
        "<arcprop id=""HeadingVisibilityA"">" & _
        "<visibility>True</visibility>" & _
        "<enabled>True</enabled>" & _
        "</arcprop>" & _
        "<arcprop id= ""HeadingVisibilityR"">" & _
        "<visibility>False</visibility>" & _
        "<checked>True></checked>" & _
        "</arcprop>" & _
        "</RCDP>"
  MsgBox ActiveDocument.CustomXMLParts(4).NamespaceURI 'Returns and empty string because there is no default namespace associted with the part.
  MsgBox ActiveDocument.CustomXMLParts(5).NamespaceURI
  MsgBox ActiveDocument.CustomXMLParts(6).NamespaceURI
  MsgBox ActiveDocument.CustomXMLParts(4).NamespaceManager.Item(1).NamespaceURI
  MsgBox ActiveDocument.CustomXMLParts(5).NamespaceManager.Item(1).NamespaceURI
  MsgBox ActiveDocument.CustomXMLParts(6).NamespaceManager.Item(1).NamespaceURI
  MsgBox ActiveDocument.CustomXMLParts(6).NamespaceManager.Item(2).NamespaceURI
  
  Dim oCPM  As CustomXMLPrefixMappings
  Set oCPM = ActiveDocument.CustomXMLParts(6).NamespaceManager
  oCPM.AddNamespace "xs", "EEEEEEEEEE"
  For i = 1 To oCPM.Count
    MsgBox oCPM.Item(i).Prefix & " " & oCPM.Item(i).NamespaceURI
  Next i
End Sub
__________________
Greg Maxey
Please visit my web site at http://www.gregmaxey.com/
Reply With Quote
  #7  
Old 06-12-2017, 02:06 AM
slaycock slaycock is offline Problem adding a namespace for customxml Windows 7 64bit Problem adding a namespace for customxml Office 2013
Expert
Problem adding a namespace for customxml
 
Join Date: Sep 2013
Posts: 255
slaycock is on a distinguished road
Default

Thanks for the revised example. Especially the CustomXMLMappings part. Your input has been extremely helpful.

I think I'm still a ways off fully understanding the nuances for MS XML management however I am now at a place where I can replicate reading and writing to a CustomDocumentProperty so can escape the restrctions of 256 character string length limits.

1. I can create a name space
2. I can add add/remove node elements
3. I can add/remove nodes with attributes
4. using an ID attribute I can find any single node
5. I can change the value of elements for a selected node

This will enable me to move a bunch custom document properties used to record information that needs to persist across editing sessions to xml, and more importantly simplify greatly the links to the various checkboxes and buttons in a custom ribbonUI as I can now use the identifiers for persistent values as the Custom UI identifiers and as keys into a dictionary of dictionaries (used to save the property value and the state of the Ribbon control).
Reply With Quote
  #8  
Old 06-12-2017, 04:06 AM
gmaxey gmaxey is offline Problem adding a namespace for customxml Windows 7 32bit Problem adding a namespace for customxml Office 2016
Expert
 
Join Date: May 2010
Location: Brasstown, NC
Posts: 1,589
gmaxey is a jewel in the roughgmaxey is a jewel in the roughgmaxey is a jewel in the roughgmaxey is a jewel in the rough
Default

Glad to help. Your project sounds interesting. Why don't you post a sample of your code showing processes 1 throughout 5 above?
__________________
Greg Maxey
Please visit my web site at http://www.gregmaxey.com/
Reply With Quote
  #9  
Old 06-12-2017, 05:40 AM
slaycock slaycock is offline Problem adding a namespace for customxml Windows 7 64bit Problem adding a namespace for customxml Office 2013
Expert
Problem adding a namespace for customxml
 
Join Date: Sep 2013
Posts: 255
slaycock is on a distinguished road
Default

Will do. It may take a few days for me to get it all in place.
Reply With Quote
  #10  
Old 06-13-2017, 09:59 AM
slaycock slaycock is offline Problem adding a namespace for customxml Windows 7 64bit Problem adding a namespace for customxml Office 2013
Expert
Problem adding a namespace for customxml
 
Join Date: Sep 2013
Posts: 255
slaycock is on a distinguished road
Default

OK. Here is my initial stab at replicating the functionality (and a bit more) that I need to replace using Custom Document properties.

Apologies for the big post and for any bugs I haven't yet found.

The first part is a class which needs to be named 'clsMyUserXMLManager' as per the use in the testing suite.

Code:
Option Explicit

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
'  I wish to use an XML data structure of the form to replace the use of Custom Document Properties
'  and to remove the need for multiple other related variables for various bits of Ribbon Controls
'
' <root xmlns=myNamespace>
'   <property id="uniquename1">
'       <Value1>Value1</value1>  'each value is an element
'       <value2>Value2</value2>
'       <value3>Value3</value2>
'   <property id="uniquename2">
'       <Value1>Value1</value1>
'       <value2>Value2</value2>
'       <value3>Value3</value2>'
'   <property id="uniquename3">
'       <Value1>Value1</value1>
'       <value2>Value2</value2>
'       <value3>Value3</value2>'
'    </property>
'</Root>
'
' Whilst Word's CustomXMLParts will create the above it also insists on inserting namespace prefixes e.g.
' The output from the complete testing suite is provided below.
'
'<?xml version="1.0"?>
'<arcRoot xmlns="MyUserNS">                         ' This namespace is my addition
'   <arcProp ns0:ID="myProp1" xmlns:ns0="myUserNS"> ' The prefix here has been 'kindly' inserted by CustomXMLParts
'       <Checked>False</Checked>
'       <Enabled>True</Enabled>
'       <Value>True</Value>
'   </arcProp>
'   <arcProp ns0:ID="myProp6" xmlns:ns0="myUserNS">
'       <Visibility>True</Visibility>
'       <Checked>False</Checked>
'       <Enabled>True</Enabled>
'   </arcProp>
'   <arcProp ns0:ID="myProp7" xmlns:ns0="MyUserNS">
'       <Value>True</Value>
'       <Visibility>True</Visibility>
'       <Checked>False</Checked>
'       <Enabled>True</Enabled>
'   </arcProp>
'   <arcProp ns0:ID="myProp8" xmlns:ns0="MyUserNS">
'       <Visibility>True</Visibility>
'       <Checked>False</Checked>
'       <Enabled>True</Enabled>
'       <Value>True</Value>
'   </arcProp>
'   <arcProp ns0:ID="myProp9" xmlns:ns0="MyUserNS">
'       <Visibility>True</Visibility>
'       <Checked>False</Checked>
'       <Enabled>True</Enabled>
'       <Value>True</Value>
'   </arcProp>
'</arcRoot>

' This XML allows me to consolidate to the same string for use as a dictionary key, ribbon control ID,
' and replace the custom document property I was previously using.
'
' 1.  Values that need to be persistent across editing sessions
' 2.  Associate ribbon controls with a persistent value if needed
' 3.  Exactly replicate the structure of a dictionary of dictionaries
'
'  Whilst reading and writing the XML may be slow compared to changing values in a scripting.dictionary
'  because the use is relatively infrequent it may be an acceptable overhead and consequently
'  it may be now possible to also eliminate the planned dictionary of dictionaries.


Const arcNS                         As String = "MyUserNS"
Const varID                         As String = "<varID>"
Const varPrefix                     As String = "<varPrefix>"

' Xpaths
' These constants contain markers of the form <varXXXX>
' At the point of use <varXXX> will be replaced by the VBA replace function
' e.g.  myXPath = replace(arcProperty,"<varID>","Identifier")

Const arcRootXPath                  As String = "//<varPrefix>arcRoot"
Const arcPropertyXPath              As String = "//<varPrefix>arcProp[@<varPrefix>ID=""<varID>""]"
Const arcNSRootXML                  As String = "<arcRoot xmlns=""MyUserNS""></arcRoot>"
Const arcProperty                   As String = "arcProp"

Private arcXMLPart                  As CustomXMLPart
Private arcPrefix                   As String

Private Sub Class_Initialize()

 Dim myPrefixMapping                As CustomXMLPrefixMappings
 Dim myPart                         As CustomXMLPart
 
    With ActiveDocument
        For Each myPart In .CustomXMLParts
            If myPart.NamespaceURI = arcNS Then
                Set arcXMLPart = .CustomXMLParts(arcNS)
                ' sbInstantiatePropertyAndRibbonControls
                Exit For
            End If
        Next
        If arcXMLPart Is Nothing Then
            .CustomXMLParts.Add XML:=arcNSRootXML
            Set arcXMLPart = .CustomXMLParts(arcNS)
        End If
        
        Set myPrefixMapping = .CustomXMLParts(arcNS).NamespaceManager
        ' Despite the fact that we have not set a prefix for our namespace, CustomXMLParts 'helpfully' adds a prefix statement to each
        ' xml statement that we add.  Therefore we need to preserve the prefix to do anything useful
        arcPrefix = myPrefixMapping.Item(1).Prefix & ":"
    End With
    
End Sub

Private Function fnNodeXpath(Property As String, Optional Child As String = vbNullString) As String

Dim myNodeXPath As String

    myNodeXPath = Replace(arcPropertyXPath, varID, Property)
    myNodeXPath = Replace(myNodeXPath, varPrefix, arcPrefix)
    If Not Child = vbNullString Then
        myNodeXPath = myNodeXPath & "/" & arcPrefix & Child
    End If
    fnNodeXpath = myNodeXPath
    
End Function


Public Function Exists(Property As String, Optional Child As String = vbNullString) As Boolean

    If arcXMLPart.SelectSingleNode(fnNodeXpath(Property:=Property, Child:=Child)) Is Nothing Then
        Exists = False
    Else
        Exists = True
    End If
End Function

Public Function Count(Optional Property As String = vbNullString) As Long
    Dim myNodes                     As CustomXMLNodes
    
    If Property = vbNullString Then
        Set myNodes = arcXMLPart.SelectNodes("//ns0:arcRoot/ns0:arcProp")
        Count = myNodes.Count

    Else
        Set myNodes = arcXMLPart.SelectNodes(fnNodeXpath(Property:=Property)).Item(1).ChildNodes
        Count = myNodes.Count
    End If
    

End Function

Public Function Properties() As Variant

' Returns a variant array containing strings representing the ID attribute for each property
' This allows easy iteration over the collection of properties as per the test demonstration

Dim myProperties                        As Long
Dim myIndex                             As Long
Dim myArray()                           As Variant
Dim myPropertyXPath                     As String

    myProperties = Count()
    ReDim myArray(myProperties)
    For myIndex = 1 To myProperties
        myPropertyXPath = arcRootXPath & "/" & arcPrefix & arcProperty & "[" & CStr(myIndex) & "]"
        myPropertyXPath = Replace(myPropertyXPath, varPrefix, arcPrefix)
        myArray(myIndex) = arcXMLPart.SelectSingleNode(myPropertyXPath).Attributes(1).Text
    Next
        
    Properties = myArray
End Function


Public Function AddProperty(NodeID As String) As Boolean

Const myPropertyIDTag               As String = "ID"

Dim myParentNode                    As CustomXMLNode
Dim myprefix                        As String

    If Exists(Property:=NodeID) Then
        Debug.Print "clsMyUserXMLManager.addProperty: Property already exists - identifier->" & NodeID
        AddProperty = False
    Else
        With arcXMLPart
            Set myParentNode = .SelectSingleNode(Replace(arcRootXPath, varPrefix, arcPrefix))
            .AddNode Parent:=myParentNode, Name:=arcProperty, NamespaceURI:=arcNS
            .AddNode Parent:=myParentNode.LastChild, Name:=myPropertyIDTag, NamespaceURI:=arcNS, NodeType:=msoCustomXMLNodeAttribute, NodeValue:=NodeID
            AddProperty = True
        End With
   End If
End Function

Public Function AddElement(NodeID As String, Name As String, Value As String) As Boolean

Dim myNodeXPath                     As String
Dim myParentNode                    As CustomXMLNode

    ' Trap the case where the property does not exists
    If Not Exists(Property:=NodeID) Then
        Debug.Print "clsMyUserXMLManager.addElement: Node for Element does not exist - property/element->" & NodeID & "/" & Name
        AddElement = False
        Exit Function
    End If
        
    ' The property exists so now trap the case where the element already exists
    If Exists(Property:=NodeID, Child:=Name) Then
        Debug.Print "clsMyUserXMLManager.addElement: Element already exists - property/element->" & NodeID & "/" & Name
        AddElement = False
    Exit Function
    End If
        
    ' The node exists but the element doesn't so add the new element
    Set myParentNode = arcXMLPart.SelectSingleNode(fnNodeXpath(Property:=NodeID))
    arcXMLPart.AddNode Parent:=myParentNode, Name:=Name, NodeValue:=Value, NamespaceURI:=arcNS, NodeType:=msoCustomXMLNodeElement
    AddElement = True
End Function

Public Property Let Value(Property As String, Child As String, Value As Variant)

Dim myNodeXPath                  As String
Dim myXMLValue                  As String

    If Not Exists(Property:=Property, Child:=Child) Then
        Debug.Print "clsMyUserXMLManager.Value: Node does not exists - identifier/child->" & Property & "/" & Child
        Exit Property
    End If
        
    myXMLValue = TypeName(Value) & "," & CStr(Value)
    ActiveDocument.CustomXMLParts(arcNS).SelectSingleNode(fnNodeXpath(Property:=Property, Child:=Child)).Text = myXMLValue
    
End Property


Public Property Get Value(Property As String, Child As String) As Variant

Dim myXMLValue                  As String
Dim myType                      As String
Dim myValue                     As String

    If Not Exists(Property:=Property, Child:=Child) Then
        Value = vbEmpty
        Exit Property
    End If
    
    myXMLValue = ActiveDocument.CustomXMLParts(arcNS).SelectSingleNode(fnNodeXpath(Property:=Property, Child:=Child)).Text
    myType = Split(myXMLValue, ",")(0)
    myValue = Split(myXMLValue, ",")(1)
    
    Select Case myType
        Case "Boolean":             Value = CBool(myValue)
        Case "Integer", "Long":     Value = CLng(myValue)
        Case "String":              Value = myValue
        Case Else
            Debug.Print "Type not implemented ->" & myType
    End Select
   
End Property


Public Function Delete(Property As String, Optional Child As String = vbNullString) As Boolean

Dim myNodeXPath                 As String

    If Not Exists(Property:=Property, Child:=Child) Then
        Debug.Print "clsMyUserXMLManager.Delete Property does not exist ->" & Property
        Delete = False
        Exit Function
    End If
    
    arcXMLPart.SelectSingleNode(fnNodeXpath(Property:=Property, Child:=Child)).Delete
    Delete = True
End Function

Private sub sbInstantiatePropertyAndRibbonControls()

    ' The next step !!!!!!
        
End Function
and the test suite I've used so far (which obviously grew like topsy) sits in a standard module

Code:
Sub testCDPReplacment()

Dim docXML As clsmyUserXMLManager
Dim myValue As Variant
Dim myName As Variant
Dim myPropertyList As Variant

    'DeleteAllCustomXML  'Sorry you'll have to write your own
    
    ' Create the root with namespace
    Set docXML = New clsmyUserXMLManager
  
    
    ' add properties
    docXML.AddProperty NodeID:="myProp1"
    docXML.AddProperty NodeID:="myProp2"
    docXML.AddProperty NodeID:="myProp6"
    docXML.AddProperty NodeID:="myProp7"
    docXML.AddProperty NodeID:="myProp8"
    docXML.AddProperty NodeID:="myProp9"

    
    
    
    ' should produce an exists error
    docXML.AddProperty NodeID:="myProp2"

    ' add elements to properties
    docXML.AddElement NodeID:="myProp1", Name:="Visibility", Value:="True"
    docXML.AddElement NodeID:="myProp1", Name:="Checked", Value:="False"
    docXML.AddElement NodeID:="myProp1", Name:="Enabled", Value:="True"
    docXML.AddElement NodeID:="myProp1", Name:="Value", Value:=True  ' this is boolean
    
    docXML.AddElement NodeID:="myProp6", Name:="Visibility", Value:="True"
    docXML.AddElement NodeID:="myProp6", Name:="Checked", Value:="False"
    docXML.AddElement NodeID:="myProp6", Name:="Enabled", Value:="True"
    
    docXML.AddElement NodeID:="myProp7", Name:="Value", Value:=True  ' this is boolean
    docXML.AddElement NodeID:="myProp7", Name:="Visibility", Value:="True"
    docXML.AddElement NodeID:="myProp7", Name:="Checked", Value:="False"
    docXML.AddElement NodeID:="myProp7", Name:="Enabled", Value:="True"
    
    docXML.AddElement NodeID:="myProp8", Name:="Visibility", Value:="True"
    docXML.AddElement NodeID:="myProp8", Name:="Checked", Value:="False"
    docXML.AddElement NodeID:="myProp8", Name:="Enabled", Value:="True"
    docXML.AddElement NodeID:="myProp8", Name:="Value", Value:=True  ' this is boolean

    docXML.AddElement NodeID:="myProp9", Name:="Visibility", Value:="True"
    docXML.AddElement NodeID:="myProp9", Name:="Checked", Value:="False"
    docXML.AddElement NodeID:="myProp9", Name:="Enabled", Value:="True"
    docXML.AddElement NodeID:="myProp9", Name:="Value", Value:=True  ' this is boolean

    
    ' this should produce an already exists error
    docXML.AddElement NodeID:="myProp1", Name:="Enabled", Value:="True"
    
    ' add element to non existent node
    docXML.AddElement NodeID:="myProp4", Name:="Visibiliy", Value:=123456789

    ' check for existence of properties
    If docXML.Exists("myProp1") Then
        Debug.Print "Property myProp1 found true = true"
    Else
        Debug.Print "Property myProp1 found true = false"
    End If
    
    'check for existnce of element
    If docXML.Exists(Property:="myProp1", Child:="Visibility") Then
        Debug.Print "Element Visibility found true = true"
    Else
        Debug.Print "Element visibility found true = false"
    End If
    
    ' Try changeing values of elements
    docXML.Value(Property:="myProp1", Child:="Visibility") = 32         ' number
    myValue = docXML.Value(Property:="myProp1", Child:="Visibility")
    Debug.Print TypeName(myValue) & " " & myValue
    
    docXML.Value(Property:="myProp1", Child:="Visibility") = True       'boolean
    myValue = docXML.Value(Property:="myProp1", Child:="Visibility")
    Debug.Print TypeName(myValue) & " " & myValue
    
    docXML.Value(Property:="myProp1", Child:="Visibility") = "True"     'string
    myValue = docXML.Value(Property:="myProp1", Child:="Visibility")
    Debug.Print TypeName(myValue) & " " & myValue

    ' delete at element level
    docXML.Delete Property:="myProp1", Child:="Visibility"
    
    If docXML.Exists(Property:="myProp1", Child:="Visibility") Then
        Debug.Print "Deletion failed"
    Else
        Debug.Print "Deletion succeeeded"
    End If
    
    'delete at property level
    docXML.Delete Property:="myProp2"
    
    If docXML.Exists(Property:="myProp2") Then
        Debug.Print "Deletion failed"
    Else
        Debug.Print "Deletion succeeeded"
    End If
    
    Debug.Print "Total properties = " & docXML.Count
    Debug.Print "Total elements in property  = " & docXML.Count(Property:="myProp8")
    
    '  testing that we have correctly retrieved the aray of property IDs
    myPropertyList = docXML.Properties
    For Each myName In myPropertyList
        Debug.Print myName
    Next
    
End Sub

I think the CustomXMLParts bit of Word is still a bit of a black box. It took me a day and a half to figure out that Word was adding prefixes behind my back and to update my code to easily accommodate that.

I have now a substantial amount of code that I need to updated to replace the use of Custom Document Properties and Associated Ribbon controls so don't be surprised if you hear the distant sound of a head banging on a brick wall over the next few weeks.

Please let me know if you find any stupidities or other errors.
Reply With Quote
  #11  
Old 06-13-2017, 06:47 PM
gmaxey gmaxey is offline Problem adding a namespace for customxml Windows 7 32bit Problem adding a namespace for customxml Office 2016
Expert
 
Join Date: May 2010
Location: Brasstown, NC
Posts: 1,589
gmaxey is a jewel in the roughgmaxey is a jewel in the roughgmaxey is a jewel in the roughgmaxey is a jewel in the rough
Default

SC,

I am far from an expert in this arena and agree with your "bit of a black box," but this aspect isn't as mystical as it may seem.

It isn't that Words CustomXMLParts insists on creating prefixes, it is if your XML uses a names space then to access the nodes you must reference the namespace prefix. If you don't name it something then Word automatically uses the default namespace prefix ns0.

Run this little demo and you can see for yourself:

Code:
Sub ScratchMacro()
'A basic Word macro coded by Greg Maxey
Dim strXML As String
Dim oXMLPart As CustomXMLPart
Dim lngIndex As Long
  For lngIndex = ActiveDocument.CustomXMLParts.Count To 4 Step -1
    ActiveDocument.CustomXMLParts(lngIndex).Delete
  Next
  'Create a simple XMLPart with an unprefixed namespace.
  strXML = "<Root xmlns='SomeNameSpace'><NodeA></NodeA><NodeB></NodeB></Root>"
  Set oXMLPart = ActiveDocument.CustomXMLParts.Add(strXML)
  'Then you must use the default namespace prefix.
  oXMLPart.SelectSingleNode("/*/ns0:NodeA[1]").Text = "Some Value"
  MsgBox oXMLPart.SelectSingleNode("/*/ns0:NodeA[1]").Text
  On Error GoTo Err_Handler:
    oXMLPart.SelectSingleNode("/*/NodeB[1]").Text = "Some Value"
    MsgBox oXMLPart.SelectSingleNode("/*/NodeA[B]").Text
lbl_ReEntry:
  Stop
  'Create a simple XMLPart without a namespace:
  strXML = "<Root><NodeA></NodeA><NodeB></NodeB></Root>"
  Set oXMLPart = ActiveDocument.CustomXMLParts.Add(strXML)
  oXMLPart.SelectSingleNode("/*/NodeA[1]").Text = "See, no namespace prefix required"
  MsgBox oXMLPart.SelectSingleNode("/*/NodeA[1]").Text
lbl_Exit:
  Exit Sub
Err_Handler:
  MsgBox Err.Number & " " & Err.Description
  Resume lbl_ReEntry
End Sub
__________________
Greg Maxey
Please visit my web site at http://www.gregmaxey.com/
Reply With Quote
  #12  
Old 06-14-2017, 12:53 AM
slaycock slaycock is offline Problem adding a namespace for customxml Windows 7 64bit Problem adding a namespace for customxml Office 2013
Expert
Problem adding a namespace for customxml
 
Join Date: Sep 2013
Posts: 255
slaycock is on a distinguished road
Default

Quote:
it is if your XML uses a names space then to access the nodes you must reference the namespace prefix. If you don't name it something then Word automatically uses the default namespace prefix ns0.
This is the bit that is confusing because it is not made clear that Word automatically adds a prefix if you define a default namespace. My understanding of XML (whilst limited) suggests that if you define a default namespace (which is what I'm doing), then prefixes are not required.

https://www.w3schools.com/xml/xml_namespaces.asp

Look under default namespaces.

Quote:
Default Namespaces
Defining a default namespace for an element saves us from using prefixes in all the child elements. It has the following syntax:

xmlns="namespaceURI"
This XML carries HTML table information:

<table xmlns="http://www.w3.org/TR/html4/">
<tr>
<td>Apples</td>
<td>Bananas</td>
</tr>
</table>
This XML carries information about a piece of furniture:

<table xmlns="https://www.w3schools.com/furniture">
<name>African Coffee Table</name>
<width>80</width>
<length>120</length>
</table>
Once I had the insight that Word was not behaving in line with the reading I'd been doing progress was rapid.

However, even then Word did not appear to play fair. This is the XML output from the test suite above.

Code:
<?xml version="1.0"?>

<arcRoot xmlns="MyUserNS">
	<arcProp ns0:ID="myProp1" xmlns:ns0="MyUserNS">
		<Checked>False</Checked>
		<Enabled>True</Enabled>
		<Value>True</Value>
	</arcProp>
	<arcProp ns0:ID="myProp6" xmlns:ns0="MyUserNS">
		<Visibility>True</Visibility>
		<Checked>False</Checked>
		<Enabled>True</Enabled>
	</arcProp>
	<arcProp ns0:ID="myProp7" xmlns:ns0="MyUserNS">
		<Value>True</Value>
		<Visibility>True</Visibility>
		<Checked>False</Checked>
		<Enabled>True</Enabled>
	</arcProp>
	<arcProp ns0:ID="myProp8" xmlns:ns0="MyUserNS">
		<Visibility>True</Visibility>
		<Checked>False</Checked>
		<Enabled>True</Enabled>
		<Value>True</Value>
	</arcProp>
-	<arcProp ns0:ID="myProp9" xmlns:ns0="MyUserNS">
		<Visibility>True</Visibility>
		<Checked>False</Checked>
		<Enabled>True</Enabled>
		<Value>True</Value>
	</arcProp>
</arcRoot>
As you can see the elements of each property do not use a prefix. However in my code it *WAS* necessary to add a prefix in the VBA code to access the elements (this is in line with the prefix examples fiven earlier in the W3 reference).

I'm happy to accept that my understanding of CustomXMLParts and XML is insufficient which is why I think I'm seeing discontinuities but the evidence to date suggests not.
Reply With Quote
  #13  
Old 06-15-2017, 04:45 PM
gmaxey gmaxey is offline Problem adding a namespace for customxml Windows 7 32bit Problem adding a namespace for customxml Office 2016
Expert
 
Join Date: May 2010
Location: Brasstown, NC
Posts: 1,589
gmaxey is a jewel in the roughgmaxey is a jewel in the roughgmaxey is a jewel in the roughgmaxey is a jewel in the rough
Default

SC,

I tinkered a bit and thought I would share the findings:

Code:
Sub ScratchMacro()
'A basic Word macro coded by Greg Maxey
Dim strXML As String
Dim oXMLPart As CustomXMLPart
Dim lngIndex As Long
  For lngIndex = ActiveDocument.CustomXMLParts.Count To 4 Step -1
    ActiveDocument.CustomXMLParts(lngIndex).Delete
  Next
  'Create a simple XMLPart without a namespace.
  strXML = "<Root><NodeA>No namespace prefix required in XPath</NodeA></Root>"
  Set oXMLPart = ActiveDocument.CustomXMLParts.Add(strXML)
   MsgBox oXMLPart.SelectSingleNode("/*/NodeA[1]").Text
  'Create a simple XMLPart with an unprefixed default namespace.
  strXML = "<Root xmlns='SomeNameSpace'><NodeA>Default prefix ns0 required in xPath</NodeA></Root>"
  Set oXMLPart = ActiveDocument.CustomXMLParts.Add(strXML)
  'Then you must use the default namespace prefix.
  MsgBox oXMLPart.SelectSingleNode("/*/ns0:NodeA[1]").Text
  'Create a simple XMLPart with a prefixed namespace:
  strXML = "<Root xmlns:a='SomeNameSpace'><a:NodeA>You can use the default prefix ns0</a:NodeA><a:NodeB></a:NodeB></Root>"
  Set oXMLPart = ActiveDocument.CustomXMLParts.Add(strXML)
  MsgBox oXMLPart.SelectSingleNode("/*/ns0:NodeA[1]").Text
  On Error Resume Next
  MsgBox oXMLPart.SelectSingleNode("/*/a:NodeC[1]").Text
  If Err.Number <> 0 Then
    oXMLPart.NamespaceManager.AddNamespace "a", "SomeNameSpace"
    oXMLPart.SelectSingleNode("/*/a:NodeA[1]").Text = "Before using your custom namespace prefixe you must add it to the XMLPart with the NamespaceManager"
     MsgBox oXMLPart.SelectSingleNode("/*/a:NodeA[1]").Text
  End If
lbl_Exit:
  Exit Sub
End Sub
__________________
Greg Maxey
Please visit my web site at http://www.gregmaxey.com/
Reply With Quote
Reply



Similar Threads
Thread Thread Starter Forum Replies Last Post
Problem batch adding autotext using Greg Maxey's Building Blocks Add-In Genuine Gin Word VBA 5 12-16-2015 10:20 AM
Problem Sending Command to the Program - Office or Windows Problem ?? JosieNurse Office 0 04-21-2015 11:49 AM
Problem adding a namespace for customxml Problem with Resolution when adding a picture in 2010 Zimm PowerPoint 1 11-13-2013 12:15 PM
Problem adding a namespace for customxml Problem with adding a footnote in Word Swarles_Barkley Word 1 11-12-2013 11:42 PM
Problem adding a namespace for customxml Adding Image into a excel cell and adding a hyperlink to the image saravananiyyanar Excel 3 05-04-2011 08:31 AM

Other Forums: Access Forums

All times are GMT -7. The time now is 08:16 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2025, vBulletin Solutions Inc.
Search Engine Optimisation provided by DragonByte SEO (Lite) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
MSOfficeForums.com is not affiliated with Microsoft