![]() |
#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 | 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 |
![]() |
Zimm | PowerPoint | 1 | 11-13-2013 12:15 PM |
![]() |
Swarles_Barkley | Word | 1 | 11-12-2013 11:42 PM |
![]() |
saravananiyyanar | Excel | 3 | 05-04-2011 08:31 AM |