I try to understand how the XML mapping with a RepeatingSection content control for Word 2013 (and above) works.
There is a sample in the Microsoft documentation that works and fills a table with three books:
Sub testRepeatingSectionControl()
Dim objRange As Range
Dim objTable As Table
Dim objCustomPart As CustomXMLPart
Dim objCC As ContentControl
Dim objCustomNode As CustomXMLNode
Dim wdDoc As Word.Document
Dim bResult As Boolean
Set wdDoc = Application.Documents.Add
Set objCustomPart = ActiveDocument.CustomXMLParts.Add
objCustomPart.LoadXML ("<books>" & _
"<book><title>Everyday Italian</title>" & _
"<author>Giada De Laurentiis</author></book>" & _
"<book><title>Harry Potter</title>" & _
"<author>J K. Rowling</author></book>" & _
"<book><title>Learning XML</title>" & _
"<author>Erik T. Ray</author></book></books>")
Set objRange = ActiveDocument.Paragraphs(1).Range
Set objTable = ActiveDocument.Tables.Add(objRange, 2, 2)
With objTable.Borders
.InsideLineStyle = wdLineStyleSingle
.OutsideLineStyle = wdLineStyleDouble
End With
Set objRange = objTable.Cell(1, 1).Range
Set objCustomNode = objCustomPart.SelectSingleNode("/books[1]/book[1]/title[1]")
Set objCC = ActiveDocument.ContentControls.Add(wdContentControlText, objRange)
bResult = objCC.XMLMapping.SetMappingByNode(objCustomNode)
Debug.Print bResult
Set objRange = objTable.Cell(1, 2).Range
Set objCustomNode = objCustomPart.SelectSingleNode("/books[1]/book[1]/author[1]")
Set objCC = ActiveDocument.ContentControls.Add(wdContentControlText, objRange)
bResult = objCC.XMLMapping.SetMappingByNode(objCustomNode)
Debug.Print bResult
Set objRange = objTable.Rows(1).Range
Set objCC = ActiveDocument.ContentControls.Add(wdContentControlRepeatingSection, objRange)
bResult = objCC.XMLMapping.SetMapping("/books[1]/book")
Debug.Print bResult
End Sub
But when I add a namespace only the first book appears in the table:
Sub testRepeatingSectionControl2()
Dim objRange As Range
Dim objTable As Table
Dim objCustomPart As CustomXMLPart
Dim objCC As ContentControl
Dim objCustomNode As CustomXMLNode
Dim bResult As Boolean
Dim wdDoc As Word.Document
Set wdDoc = Application.Documents.Add
Set objCustomPart = wdDoc.CustomXMLParts.Add
objCustomPart.LoadXML ("<b:books xmlns:b='urn:example.com/bib'>" & _
"<b:book><b:title>Everyday Italian</b:title>" & _
"<b:author>Giada De Laurentiis</b:author></b:book>" & _
"<b:book><b:title>Harry Potter</b:title>" & _
"<b:author>J K. Rowling</b:author></b:book>" & _
"<b:book><b:title>Learning XML</b:title>" & _
"<b:author>Erik T. Ray</b:author></b:book>" & _
"</b:books>")
Call objCustomPart.namespaceManager.AddNamespace("b", "urn:example.com/bib")
Set objRange = wdDoc.Paragraphs(1).Range
Set objTable = wdDoc.Tables.Add(objRange, 2, 2)
With objTable.Borders
.InsideLineStyle = wdLineStyleSingle
.OutsideLineStyle = wdLineStyleDouble
End With
Set objRange = objTable.Cell(1, 1).Range
Set objCustomNode = objCustomPart.SelectSingleNode("/b:books[1]/b:book[1]/b:title[1]")
Set objCC = wdDoc.ContentControls.Add(wdContentControlText, objRange)
bResult = objCC.XMLMapping.SetMappingByNode(objCustomNode)
Debug.Print bResult
Set objRange = objTable.Cell(1, 2).Range
Set objCustomNode = objCustomPart.SelectSingleNode("/b:books[1]/b:book[1]/b:author[1]")
Set objCC = wdDoc.ContentControls.Add(wdContentControlText, objRange)
bResult = objCC.XMLMapping.SetMappingByNode(objCustomNode)
Debug.Print bResult
Set objRange = objTable.Rows(1).Range
Set objCC = wdDoc.ContentControls.Add(wdContentControlRepeatingSection, objRange)
bResult = objCC.XMLMapping.SetMapping("/b:books[1]/b:book")
Debug.Print bResult
End Sub
Since the XML and the XPath expressions seems to be valid for me it could be a bug in Word 2013 as it has been stated in this post (I have no tested the code with newer versions of Word yet)
Word 2013: VBA Insert Content Control mapped to existing Custom XML
AFAICS the problem is that SetMapping does not recognize mappings that you have associated with a Custom XML Part using .AddNameSpace. This doesn't seem consistent to me, but that is the conclusion my own tests (using the current version of Word) led me to.
That is, when you use SelectSingleNode to find a node in a Part, Word honors the prefix mapping that you created. When you issue SetMappingByNode, there is enough information for Word to determine the exact Node in the exact Part.
So you could do the mapping using the same technique, e.g.
Set objCC = wdDoc.ContentControls.Add(wdContentControlRepeatingSection, objRange)
Set objCustomNode = objCustomPart.SelectSingleNode("/b:books[1]/b:book[1]")
bResult = objCC.XMLMapping.SetMappingByNode(objCustomNode)
But if you use SetMapping, I would assume that you would at least have to identify the Part (because the prefix mapping is associated with the Part, and therefore your b
mapping wouldn't mean anything to Word otherwise. So you might hope that the following would succeed:
bResult = objCC.XMLMapping.SetMapping("/b:books[1]/b:book",,objCustomPart)
But that also fails. OTOH if you specify the mapping in the call, it works, and nor do you actually need the reference to the Part (at least not in this case, although it may speed up the mapping process because otherwise AIUI Word will look through the Parts until it finds a match for the XPath expression):
bResult = objCC.XMLMapping.SetMapping("/b:books[1]/b:book", "xmlns:b='urn:example.com/bib')
Alternatively, you can discover what mapping Word understands by looking up the namespace prefix that Word recognizes (which was the approach taken by @CindyMeister in the article you referenced). e.g.
Dim p As String
p = objCustomPart.NamespaceManager.LookupPrefix("urn:example.com/bib")
Debug.Print p
bResult = objCC.XMLMapping.SetMapping("/" & p & ":books[1]/" & p & ":book")