我已经成功地使用C# OpenXml SDK (来自NuGet的非官方MicrosoftPackage2.5)一段时间了,但最近注意到以下代码行返回不同的结果,这取决于保存文件时Microsoft Word的状态:
var fields = document.Descendants<FieldCode>();据我所知,在创建文档时(使用Windows8.1上的Word 2013 ),如果您使用Insert->QuickParts->Field并从字段名称左侧窗格中选择MergeField,然后在字段属性中提供一个字段名称并单击OK,那么字段代码就会像我所期望的那样正确地保存在文档中。
然后,当使用前面提到的代码行时,我将收到1 field的field code count。如果我随后编辑了这个文档(甚至保留了这个字段),那么随后的保存可能意味着我的查询中不再返回这个字段代码。
同样令人好奇的另一个例子是,当我看到FieldCode节点被拆分到多个项目时。所以,与其看,不如说:
" MERGEFIELD Author \\* MERGEFORMAT "作为节点名,我将看到:
" MERGEFIELD Aut"
"hor \\* MERGEFORMAT"拆分为两个FieldCode节点值。我不知道为什么会这样,但这肯定会使我匹配节点的能力变得更加令人兴奋。这是预期的行为吗?一个已知的bug?我真的不想打开原始的xml并编辑这个文档来工作,直到我理解发生了什么。非常感谢大家。
发布于 2017-06-13 00:51:55
我自己遇到了这个问题,并在OpenXML中找到了一个解决方案:一个名为MarkupSimplifier的实用程序类,它是PowerTools for Open XML项目的一部分。使用这个类解决了你所描述的我遇到的所有问题。
The full article is located here.
以下是一些相关的练习:
执行的最有用的简化可能是合并具有相同格式的相邻运行。
它接着说:
Open XML应用程序,包括Word,可以根据需要任意拆分运行。例如,如果您向文档添加注释,则运行将在注释的开始和结束位置拆分。在MarkupSimplifier删除注释后,它可以合并运行,从而使标记更简单。
正在使用的实用程序类的一个示例是:
SimplifyMarkupSettings settings = new SimplifyMarkupSettings
{
RemoveComments = true,
RemoveContentControls = true,
RemoveEndAndFootNotes = true,
RemoveFieldCodes = false,
RemoveLastRenderedPageBreak = true,
RemovePermissions = true,
RemoveProof = true,
RemoveRsidInfo = true,
RemoveSmartTags = true,
RemoveSoftHyphens = true,
ReplaceTabsWithSpaces = true,
};
MarkupSimplifier.SimplifyMarkup(wordDoc, settings);我在使用VS2015 .Net框架4.5.2的Word 2010文档中多次使用它,它让我的生活变得非常非常轻松。
更新
我重新查看了这段代码,发现它在MERGEFIELDS上运行时会清除,但如果字段引用了合并字段,则不会清除。
{if {MERGEFIELD When39} = "Y???" "Y" "N" }我不知道为什么会这样,而且对底层XML的检查也没有提供任何提示。
发布于 2015-06-26 01:39:20
Word经常会将文本串拆分成多个文本串,这是我从未理解过的。在进行搜索、比较、整理等操作时,我们使用将多个游程组合成一个文本游程的方法对正文进行预处理。
/// <summary>
/// Combines the identical runs.
/// </summary>
/// <param name="body">The body.</param>
public static void CombineIdenticalRuns(W.Body body)
{
List<W.Run> runsToRemove = new List<W.Run>();
foreach (W.Paragraph para in body.Descendants<W.Paragraph>())
{
List<W.Run> runs = para.Elements<W.Run>().ToList();
for (int i = runs.Count - 2; i >= 0; i--)
{
W.Text text1 = runs[i].GetFirstChild<W.Text>();
W.Text text2 = runs[i + 1].GetFirstChild<W.Text>();
if (text1 != null && text2 != null)
{
string rPr1 = "";
string rPr2 = "";
if (runs[i].RunProperties != null) rPr1 = runs[i].RunProperties.OuterXml;
if (runs[i + 1].RunProperties != null) rPr2 = runs[i + 1].RunProperties.OuterXml;
if (rPr1 == rPr2)
{
text1.Text += text2.Text;
runsToRemove.Add(runs[i + 1]);
}
}
}
}
foreach (W.Run run in runsToRemove)
{
run.Remove();
}
}发布于 2020-03-09 23:55:25
我试图用Powertools简化文档,但结果是一个损坏的word文件。我将此例程设置为只简化具有特定名称的字段代码,它适用于文档的所有部分(主要文档部分、页眉和页脚):
internal static void SimplifyFieldCodes(WordprocessingDocument document)
{
var masks = new string[] { Constants.VAR_MASK, Constants.INP_MASK, Constants.TBL_MASK, Constants.IMG_MASK, Constants.GRF_MASK };
SimplifyFieldCodesInElement(document.MainDocumentPart.RootElement, masks);
foreach (var headerPart in document.MainDocumentPart.HeaderParts)
{
SimplifyFieldCodesInElement(headerPart.Header, masks);
}
foreach (var footerPart in document.MainDocumentPart.FooterParts)
{
SimplifyFieldCodesInElement(footerPart.Footer, masks);
}
}
internal static void SimplifyFieldCodesInElement(OpenXmlElement element, string[] regexpMasks)
{
foreach (var run in element.Descendants<Run>()
.Select(item => (Run)item)
.ToList())
{
var fieldChar = run.Descendants<FieldChar>().FirstOrDefault();
if (fieldChar != null && fieldChar.FieldCharType == FieldCharValues.Begin)
{
string fieldContent = "";
List<Run> runsInFieldCode = new List<Run>();
var currentRun = run.NextSibling();
while ((currentRun is Run) && currentRun.Descendants<FieldCode>().FirstOrDefault() != null)
{
var currentRunFieldCode = currentRun.Descendants<FieldCode>().FirstOrDefault();
fieldContent += currentRunFieldCode.InnerText;
runsInFieldCode.Add((Run)currentRun);
currentRun = currentRun.NextSibling();
}
// If there is more than one Run for the FieldCode, and is one we must change, set the complete text in the first Run and remove the rest
if (runsInFieldCode.Count > 1)
{
// Check fielcode to know it's one that we must simplify (for not to change TOC, PAGEREF, etc.)
bool applyTransform = false;
foreach (string regexpMask in regexpMasks)
{
Regex regex = new Regex(regexpMask);
Match match = regex.Match(fieldContent);
if (match.Success)
{
applyTransform = true;
break;
}
}
if (applyTransform)
{
var currentRunFieldCode = runsInFieldCode[0].Descendants<FieldCode>().FirstOrDefault();
currentRunFieldCode.Text = fieldContent;
runsInFieldCode.RemoveAt(0);
foreach (Run runToRemove in runsInFieldCode)
{
runToRemove.Remove();
}
}
}
}
}
}希望这能有所帮助!
https://stackoverflow.com/questions/31056953
复制相似问题