2016-03-22 11 views
0

私はいくつかのVBAコードを作成しています。これらのドキュメントは、定期的に作成されており、常に異なっています。それがうまくいくならば、コンテンツコントロールとカスタムXMLから適切な価値を得ることができます。次のように私は(データのない完全なセット)XMLを定義したWord 2013:既存のカスタムXMLにマップされたVBA挿入コンテンツコントロール

<document xmlns="http://example.com/dept/doctype"> 
    <office> 
    <address>123 Sample St</address> 
    <city>Sampleville</city> 
    </office> 
    <customer> 
    <address>456 Other St</address> 
    <city>Otherville</city> 
    </customer> 
    <docinfo> 
    <refid>XaCaXaCaX</refid> 
    <docid>1</docid> 
    </docinfo> 
</document> 

私は、カスタムXML(開発者用リボン> XMLマッピングペイン>カスタムXMLパート>は新しいパーツを追加インポートしました。 ..)、データはWordに存在します。そのペインでコンテンツコントロールを挿入すると、完全に機能します。

ただし、これは期待どおりに機能しません。コンテンツコントロールが追加されても、カスタムXML部分のノードにバインドされていないため、そのノードにバインドされている他のインスタンスが変更されたときに更新されません。

Sub Test() 
    Const sNamespace = "http://example.com/dept/doctype" 
    Const sXMLOfficeAddressPath = "/document/office/address" 

    Dim oParts As CustomXMLParts 
    Dim oPart As CustomXMLPart 
    Dim oCC As ContentControl 
    Dim oRange As Range 
    On Error GoTo Err_Handler 

    Set oParts = ActiveDocument.CustomXMLParts.SelectByNamespace(sNamespace) 
    Set oPart = ActiveDocument.CustomXMLParts.SelectByID(oParts.Item(1).ID) 

    ActiveDocument.Range.InsertParagraphBefore 

    Set oRange = ActiveDocument.Paragraphs(1).Range 
    Set oCC = ActiveDocument.ContentControls.Add(wdContentControlText, oRange) 
    oCC.XMLMapping.SetMapping sXMLOfficeAddressPath, , oPart 
    oCC.Title = "Office Address" 
    oCC.Color = wdColorBlack 
    Exit Sub 
Err_Handler: 
    MsgBox (Err.Number & ": " & Err.Description) 
End Sub 

SetMappingは決してエラーをスローしません。サイレントに失敗します。

実行時にXMLを追加すると仮定した場合のすべての例 - XMLを複数追加すると、追加されたフィールドごとに1つずつ(おそらく50以上では、迷惑な肥満の)。

どこからインスピレーションを受ける必要がありますか?

答えて

1

SetMappingメソッドでは、少なくとも名前空間が関与していないときは一度も運がありませんでした。 SetMappingByNodeは常に動作しますが、xPathが正しいことを条件とします。

xmlに名前空間がある場合(推奨!)、xPathのxmlタグを名前空間接頭辞で修飾する必要があります。次のサンプルは、ノードの取得方法と、ノードへのマッピングの設定方法を示しています。私の例では、CustomXMLPartがすでにドキュメント内にあることを前提としています。

Sub AddAndLinkContentControl() 
    Dim ns As String, nsPrefix As String 
    Dim cxp As Office.CustomXMLPart 
    Dim ccLink_xPath As String 
    Dim rng As word.Range 
    Dim cc As word.ContentControl 
    Dim ccNode As Office.CustomXMLNode 

    ns = "http://example.com/dept/doctype" 
    Set cxp = ActiveDocument.CustomXMLParts.SelectByNamespace(ns)(1) 
    nsPrefix = cxp.NamespaceManager.LookupPrefix(ns) 
    ccLink_xPath = nsPrefix & ":document/" & nsPrefix & ":office/" & nsPrefix & ":address" 
    If Not cxp Is Nothing Then 
     Set rng = Selection.Range 
     Set cc = ActiveDocument.Contentcontrols.Add(wdContentControlText, rng) 
     Set ccNode = cxp.SelectSingleNode(ccLink_xPath) 
     If Not ccNode Is Nothing Then 
      cc.XMLMapping.SetMappingByNode ccNode 
      'cc.XMLMapping.SetMapping ccLink_xPath, , cxp 'Doesn't work with namespaces 
      Debug.Print cc.XMLMapping.IsMapped 
     End If 
    End If 
End Sub 

SetMappingそれはIsMappedプロパティをチェックする必要があります理由である、エラーが発生することはありません。また、ccNode Is Nothingかどうかチェックする方法にも注意してください。これは、代入が成功しなかった場合でもエラーを発生させないためです。変数オブジェクトは単純に初期化されません。これは、XMLパーサーがどのように機能するかの典型です。

私はまた、2013年にコンテンツコントロールをカスタムxmlパーツにマッピングするツールが信頼できず、コードアプローチを使用したいと考えています。

は(あなたのサンプルコードでXPathが間違っていることに注意してください、それはあなたが提供するサンプルXMLのように、むしろ文書よりも、製品としてのルートノードを指定します。)

+0

ああ、はい、それはあなたが睡眠の時間のカップルにものをサニタイズする必要があるときに何が起こるかです。 OPを適切に更新します。 – DavidRa

1

は、私はまた、別の方法を発見していますan article by Abin Jaik Antonyのおかげでうまくいくようです。あなたは今、XMLの有効な任意の値でInsertTextFieldを呼び出すことができ

Const sNSMapping = "xmlns:ns0='http://example.com/dept/doctype'" 
Const sField = "/ns0:document[1]/ns0:office[1]/ns0:address[1]" 

Function InsertTextField(sField) 
    On Error GoTo Err_Handler 

    Dim oCC As ContentControl 
    Dim oRange As Range 

    Set oRange = Selection.Range 
    Set oCC = ActiveDocument.ContentControls.Add(wdContentControlText, oRange) 
    oCC.XMLMapping.SetMapping sField, sNSMapping 

    Exit Function 
Err_Handler: 
    If 4605 = Err.Number Then MsgBox "Error: You can't insert a data field inside another data field. Move the cursor outside the data field and try again.", vbOKOnly + vbCritical + vbApplicationModal, "Template Error" 
End Function 

注:私は、私の知る限り、合理的にできる限りそれを削減しようとしました。 sNSMappingの名前空間接頭辞は、sFieldで使用される接頭辞と一致する必要があります。これは、あなたが望む任意の接頭辞を使用できることを意味:

Const sNSMapping = "xmlns:redcar48='http://example.com/dept/doctype'" 
Const sField = "/redcar48:document[1]/redcar48:office[1]/redcar48:address[1]" 

または多分

Const sNSMapping = "xmlns:funkytown85='http://example.com/dept/doctype'" 
Const sField = "/funkytown85:document[1]/funkytown85:office[1]/funkytown85:address[1]" 
+0

このアプローチの欠点は、Wordが実際に使用するプレフィックスを予測できないことです。 XMLで割り当てる名前空間接頭辞を使用せず、ns#パターンを使用して任意の接頭辞を割り当てます。しかし、Wordが他のXMLセットを見ているときのように、数字が0になるという保証はありません。 –

+0

絶対に真実ですが、明らかになっていないのは、Wordがまったく気にしていないということです。私は二重チェックし、名前空間FunkyTown85(はい、実際は)またはSpace2001と同様に名前空間ns0と同じように実行します。 – DavidRa

+0

Mmmm。あなたが何を意味するか正確にはわからない。名前空間やプレフィックスを意味しますか?あなたは接頭辞を意味すると仮定し、あなたがxmllnsに割り当てたものを意味しています:正しいですが、どちらの接頭辞を選んでも問題ありません。 * XMLが解析されるときに* Wordが割り当てるものは重要です。 *あなたはコントロールできませんし、Wordがns0を使用することは保証されていません。 Wordが複数のXMLを解析している場合は、ns1やns2などとなります。私が言っていることは、コードが実行されている現状に応じて、sFieldが間違っている可能性があるということです。接頭辞をハードコーディングすることは「堅牢」ではありません。 –

関連する問題