InfoPathフォームのOpenXMLによる単語文書
-
28-10-2019 - |
質問
Infopath 2010フォームがあります。学生情報として設計されています。指定されたレポートテンプレートを使用してOpenXMLを使用してWord文書としてレポートを生成したいと思います。私はそのようなフォームを設計しました、
すべてのフィールドは、今のところテキストとしてInfopathフォームに配置されています。
ボタン制御を追加しました。
- ボタン]クリックで、XpathNavigatorオブジェクトを使用してフィールドの値を取得しています。
- 今、私は値を持つ文字列変数のセットを持っています。
- コンテンツコントロールを備えた.DOTXファイルを準備しました。 (各コントロールにIDを与える必要がありますか?)
ただし、C#を使用して、変数値をWord Templateコンテンツにプログラムでマップする方法を理解できません。 ここに] [1] Webを使用したOpenXMLの素晴らしい例。ただし、XMLファイルからWordテンプレートへのデータをダンプするために使用するカスタムXMLパーツを使用しています。
文字列変数をテンプレートコンテンツコントロールとマッピングするために何をしなければなりませんか?これに対する参照リンクはありますか?
解決
私は非常によく似たものを痛む必要があり、最終的には単語フィールドの代わりにカスタム「プレースホルダー」フィールドを使用することになりました(ヘッダー、フッター、ボディなど、さまざまなオブジェクトを使用してさまざまな制限があります)。
私の言葉のテンプレートでは、このようなプレースホルダーをマークしました - ## myplaceholdername!#。次に、単語テンプレートのテキストを解析して、Regexを使用してすべてのプレースホルダーを見つけ、InfoPathフォームの実際の値に置き換えました。
このソリューションの唯一の欠点は、プレースホルダーとインフォパスフィールドが同じ名前を持つ必要があることです。そうしないと、一致することはできません。
この方法を考慮してください:
private void FillDocument(Stream documentStream, string xmlFields)
{
var doc = new XmlDocument();
doc.LoadXml(xmlFields);
var props = doc.SelectSingleNode("properties");
if (props == null) throw new Exception("No properties found.");
//transform the xml properties to dictionary for easier replacement
var fields = props.ChildNodes.Cast<XmlNode>().ToDictionary
(node => string.Format("##{0}!#", node.Name), node => node.InnerText);
using (var document = WordprocessingDocument.Open(documentStream, true))
{
var main = document.MainDocumentPart;
//replace the fields in the main document
main.Document.InnerXml = ReplaceFields(main.Document.InnerXml, fields);
//replace the fields in the headers
foreach (var headerPart in main.HeaderParts)
headerPart.Header.InnerXml = ReplaceFields(headerPart.Header.InnerXml, fields);
//replace the fields in the footers
foreach (var footerPart in main.FooterParts)
footerPart.Footer.InnerXml = ReplaceFields(footerPart.Footer.InnerXml, fields);
main.Document.Save();
}
}
private string ReplaceFields(string xmlPart, Dictionary<string, string> fields)
{
//searches the xml for the declared fields
var fieldRegex = new Regex("##[^#]*!#");
var matches = fieldRegex.Matches(xmlPart);
foreach (Match match in matches)
{
//the fields are within tags (InnerText) so remove all other xml stuff
var innerRegex = new Regex("<[^>]*>");
string fieldName = innerRegex.Replace(match.Groups[0].Value, "");
//replace the actual value of the field
if(fields.ContainsKey(fieldName))
xmlPart = xmlPart.Replace(match.Groups[0].Value, fields[fieldName]);
}
return xmlPart;
}
次のように使用します:
//open the file from as stream (in this example, the file is opened from SP
using (var stream = templateFile.OpenBinaryStream())
{
//iterate the properties you need and add them in this format
var xmlProperties = "<properties><MyPlaceHolderName>MyPlaceHolderValue</MyPlaceHolderName></properties>";
//fill out the fields
FillDocument(stream, xmlProperties);
}
私はXML複製とXMLPropertiesが比較的クレイジーであることを知っていますが、私の要件のためにこのように実装する必要がありました(方法はInfopathからのWebサービスによって呼び出されます)。さらに支援が必要な場合はお知らせください。