![]() |
|
|
|
#1
|
|||
|
|||
|
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
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
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
|
|
#2
|
|||
|
|||
|
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
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 |
|
#3
|
|||
|
|||
|
Looks like rubberducking has worked again
the error I made is here Code:
Dim part As CustomXMLParts Dim parts As CustomXMLParts Code:
Dim part As CustomXMLPart Dim parts As CustomXMLParts |
|
#4
|
|||
|
|||
|
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
|
|
#5
|
|||
|
|||
|
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. |
|
#6
|
|||
|
|||
|
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
|
|
#7
|
|||
|
|||
|
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). |
|
#8
|
|||
|
|||
|
Glad to help. Your project sounds interesting. Why don't you post a sample of your code showing processes 1 throughout 5 above?
|
|
#9
|
|||
|
|||
|
Will do. It may take a few days for me to get it all in place.
|
|
#10
|
|||
|
|||
|
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
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. |
|
#11
|
|||
|
|||
|
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
|
|
#12
|
|||
|
|||
|
Quote:
https://www.w3schools.com/xml/xml_namespaces.asp Look under default namespaces. Quote:
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> 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. |
|
#13
|
|||
|
|||
|
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
|
|
| Thread Tools | |
| Display Modes | |
|
|
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 with Resolution when adding a picture in 2010
|
Zimm | PowerPoint | 1 | 11-13-2013 12:15 PM |
Problem with adding a footnote in Word
|
Swarles_Barkley | Word | 1 | 11-12-2013 11:42 PM |
Adding Image into a excel cell and adding a hyperlink to the image
|
saravananiyyanar | Excel | 3 | 05-04-2011 08:31 AM |