C# WordprocessingDocument分隔文本(不必要)
我正在尝试替换word文档中的某些位置,它充当模板。这些位置标记为以C# WordprocessingDocument分隔文本(不必要),c#,xml,formatting,wordprocessingml,word-processor,C#,Xml,Formatting,Wordprocessingml,Word Processor,我正在尝试替换word文档中的某些位置,它充当模板。这些位置标记为以@开头的单词。例如@Name。我选择所有文本,用我的函数运行它们并替换。这背后的所有逻辑都运作良好。然而,由于我不知道的原因,文本的定义如下: List<Text> texts = w.MainDocumentPart.Document.Descendants<Text>().ToList(); (@ sum_ words) 即使它应该在一行中,如下所示:文档日期:@date,作者:@Name@姓氏。
@
开头的单词。例如@Name
。我选择所有文本,用我的函数运行它们并替换。这背后的所有逻辑都运作良好。然而,由于我不知道的原因,文本的定义如下:
List<Text> texts = w.MainDocumentPart.Document.Descendants<Text>().ToList();
(@
sum_
words)
即使它应该在一行中,如下所示:文档日期:@date,作者:@Name@姓氏
。如您所见,在@
和日期
或@
和姓氏
等情况下,我无法正确使用替换方法,因为没有@日期
或@姓氏
。所以我改进了我的代码,但现在我看到了其中的许多缺陷,所以它将遗漏的@
连接到下一个文本。不幸的是,我在一个表中找到了一个文本,这完全破坏了我的算法。
就是这样,
List<Text> texts = w.MainDocumentPart.Document.Descendants<Text>().ToList();
(@
sum_
words)
尽管我没有专门用不同的样式来格式化它。如你所见,它必须是(@sum_words)
,在这种情况下,我的算法很容易被替换。不幸的是,我不能。因此,我的问题是:
for (int i = texts.Count - 1; i > 0; i--)
{
if (texts[i - 1].Text.EndsWith("@") || texts[i - 1].Text.EndsWith("_"))
{
texts[i - 1].Text = texts[i - 1].Text + texts[i].Text;
texts[i].Text = "";
}
}
如果文本被分割一半,它将连接文本(据我所见,它们只在特定于我需要的字符上被分割,这些字符是@
和.
。循环是反向的,因为保存组中第一个文本部分的属性比保存最后一个文本部分的属性更有意义(例如,在图元之前保留间距)
更新2
以下是请求的表格单元格:
<w:tc>
<w:tcPr>
<w:tcW w:w="2410" w:type="dxa"/>
<w:tcBorders>
<w:top w:val="single" w:sz="4" w:space="0" w:color="auto"/>
<w:left w:val="single" w:sz="4" w:space="0" w:color="auto"/>
<w:bottom w:val="single" w:sz="4" w:space="0" w:color="auto"/>
<w:right w:val="single" w:sz="4" w:space="0" w:color="auto"/>
</w:tcBorders>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p w:rsidR="009D473B" w:rsidRDefault="00385754" w:rsidP="00385754">
<w:pPr>
<w:jc w:val="center"/>
<w:rPr>
<w:lang w:val="lt-LT"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:lang w:val="lt-LT"/>
</w:rPr>
<w:t>@sum</w:t>
</w:r>
<w:r w:rsidR="009D473B">
<w:rPr>
<w:lang w:val="lt-LT"/>
</w:rPr>
<w:t xml:space="preserve">(@</w:t>
</w:r>
<w:r>
<w:rPr>
<w:lang w:val="lt-LT"/>
</w:rPr>
<w:t>sum_</w:t>
</w:r>
<w:r w:rsidR="009D473B">
<w:rPr>
<w:lang w:val="lt-LT"/>
</w:rPr>
<w:t>words)</w:t>
</w:r>
</w:p>
</w:tc>
@总数
(@
总数_
(文字)
我在替换WordML文档中的变量时遇到的唯一问题是由于拼写和语法模块导致的,该模块倾向于插入特殊的标记来打断变量名,这可以通过在模板编辑期间完全禁用Word中的语法错误检查和标记来解决
我的替换方法是这样的(我的命名变量的约定有点不同,这一个与您的有所不同):
编辑2
我编写了一个后备方法,在上述方法不起作用的情况下替换变量(case el==null)上面。一个段落w:p可以包含多个运行,并且我们的变量名可以在连续的一系列运行中被打断。因此,我们希望识别这些运行并仅在第一个运行中替换值,删除其余的运行。我们必须小心地保留可能出现在变量名之前和之后的文本(前缀将在第一次运行中,sufix将在最后一次运行中)
publicstaticvoidassignfallback(XElement xe,字符串名称,字符串值)
{
字符串varName=“(@“+name+”);
XElement xep=xe.subjects()
.FirstOrDefault(x=>x.Name.LocalName==“p”&&x.Value.Contains(varName));
if(xep==null)
{
返回;
}
字符串前缀=”,sufix=”;
List truns=新列表();
列出allruns=xep.subjects()。其中(x=>x.Name.LocalName==“r”).ToList();
for(int i=0;ivarName.Length)
{
打破
}
}
if(名称临时启动(变量名称))
{
XElement xet=truns[0]。后代().FirstOrDefault(x=>x.Name.LocalName==“t”);
xet.Value=prefix+Value+sufix;
对于(int j=1;j
由于检查和标记是在创建模板本身的同时完成的,因此当我在C#part上打开文档本身时,是否可以手动删除这些标记、属性、属性等?例如一些magicallyRemoveCheckMarking(w)
。因为我知道说服某人不使用这些是多么不可能的事,更不用说,为了让它起作用,每个人都必须这样做。但是如果以后有办法删除这些插入内容…?一旦你有了一个XDocument或XElement对你的文档部分的引用,一切都是可能的,唯一的限制就是n是在修改后成为有效的word文档。如果您发布了有问题的节的确切xml结构,我可以帮助您。它应该看起来像…(@variable_name)…如果是word 2007+文档,您可以使用任何zip程序(例如7-zip)将.docx文件解压缩到文件夹中,或者更改ext
public static void AssignFallback(XElement xe, string name, string value)
{
string varName = "(@" + name + ")";
XElement xep = xe.Descendants()
.FirstOrDefault(x => x.Name.LocalName == "p" && x.Value.Contains(varName));
if (xep == null)
{
return;
}
string prefix = "", sufix = "";
List<XElement> truns = new List<XElement>();
List<XElement> allruns = xep.Descendants().Where(x => x.Name.LocalName == "r").ToList();
for (int i = 0; i < allruns.Count; i++)
{
if (!allruns[i].Value.Contains("(@"))
{
continue;
}
int index = allruns[i].Value.IndexOf("(@");
prefix = allruns[i].Value.Substring(0, index);
truns.Clear();
truns.Add(allruns[i]);
string nameTemp = allruns[i].Value.Substring(index, allruns[i].Value.Length - index);
if (!varName.StartsWith(nameTemp))
{
continue;
}
for (int j = i + 1; j < allruns.Count; j++)
{
nameTemp += allruns[j].Value;
truns.Add(allruns[j]);
if (nameTemp.StartsWith(varName))
{
sufix = nameTemp.Substring(varName.Length);
break;
}
else if (nameTemp.Length > varName.Length)
{
break;
}
}
if (nameTemp.StartsWith(varName))
{
XElement xet = truns[0].Descendants().FirstOrDefault(x => x.Name.LocalName == "t");
xet.Value = prefix + value + sufix;
for (int j = 1; j < truns.Count; j++)
{
truns[j].Remove();
}
}
}
}