当前位置: 首页 > 编程语言 > C#

OpenXML标签搜索Share

时间:2023-04-10 23:10:49 C#

OpenXML标签搜索的所有出现。明确一点,我不是在寻找OpenXML标签,而是应该由文档编写者设置到文档中的标签,作为我需要在第二阶段填写的值的占位符。此类标签应采用以下格式:(其中TAG可以是任何字符序列)。正如我所说,我必须找到所有出现的这些标签,再加上(如果可能的话)找到找到的标签出现的“页面”。我在网上找到了一些东西,但不止一次基本的方法是将文件的所有内容转储到一个字符串中,然后查看这样一个字符串,而不考虑.docx编码。这会导致误报或根本不匹配(而测试.docx文件包含多个标签),其他示例可能与我对OpenXML的了解有点不同。查找此类标签的正则表达式模式应该是这样的:标签可以在整个文档中找到(在表格、文本、段落内,但也可以在页眉和页脚中)。我在VisualStudio2013.NET4.5中编码,但如果需要我可以回来。PS我更喜欢不使用OfficeInteropAPI的代码,因为目标平台不会运行Office。我可以生成的最小.docx示例存储此内部文档例如,在您的示例XML中,标记被分成多个运行,如下所示:正如评论中所指出的,这有时是由拼写和语法检查引起的,但并非全部它可以。例如,标签的部分样式不同也会导致这种情况。处理此问题的一种方法是找到段落的InnerText并将其与常规正则表达式进行比较。InnerText属性将返回段落的纯文本,基础文档中没有任何格式或其他XML妨碍。有了标签后,下一个问题就是替换文本。由于上述原因,您不能只用一些新文本替换InnerText,因为不清楚文本的哪些部分属于哪个Run。执行此操作的最简单方法是删除任何现有的Run并添加一个新的Run,其Text属性包含新文本。以下代码显示查找令牌并立即替换它们,而不是像您在问题中建议的那样使用两次传递。这只是为了让事情更简单。它应该显示你需要的一切。privatestaticvoidReplaceTags(stringfilename){Regexregex=newRegex("",RegexOptions.Compiled);using(WordprocessingDocumentwordDocument=WordprocessingDocument.Open(filename,true)){//抓取标题部分并在那里替换标签}//现在做文档ReplaceParagraphParts(wordDocument.MainDocumentPart.Document,regex);//现在替换页脚部分foreach(FooterPartfooterPartinwordDocument.MainDocumentPart.FooterParts){}}}privatestaticvoidReplaceParagraphParts(OpenXmlElementelement,Regexregex){foreach(varparagraphinelement.Descendants()){Matchmatch=regex.Match(paragraph.InnerText);if(match.Success){//createanewrunandsetitsvaluetothecorrecttext//thismustbedonebeforethechildrunsareremoved否则//paragraph.InnerText将为空RunnewRun=newRun();newRun.AppendChild(newText(paragraph.InnerText.Replace(match.Value,"一些新值")));//删除任何子运行paragraph.RemoveAllChildren();//添加新创建的运行段落。AppendChild(newRun);上述方法唯一的缺点是你可能拥有的任何样式都将丢失这些可以从现有的Run中复制,但是如果有多个具有不同属性的Run,你需要确定哪些需要复制到哪里.如果需要,没有什么可以阻止您在上面的代码中创建多个Run,每个都具有不同的属性。不确定SDK是否更好,但这会生成一个包含标签名称的字典和一个可以设置新值的元素:usingSystem;使用System.Collections.Generic;使用System.Linq;使用系统文本;使用System.Text。常用表达;使用System.Threading.Tasks;使用System.Xml.Linq;namespaceConsoleApplication8{classProgram{staticvoidMain(string[]args){DictionarylookupTable=newDictionary();正则表达式reg=newRegex(@".*)!>");XDocumentdoc=XDocument.Load("document.xml");XNamespacens=doc.Root.GetNamespaceOfPrefix("w");IEnumerable元素=doc.Root.Descendants(ns+"t")。Where(x=>x.Value.StartsWith("编辑:您可以制作的可能结构的更完整示例:使用System;使用System.Collections.Generic;使用System.Linq;使用System.Text;使用System.Threading.任务;使用System.Xml.Linq;使用System.IO.Compression;//您必须添加对System.IO.Compression.FileSystem(.dll)的引用使用System.IO;使用System.Text.RegularExpressions;ConsoleApplication28{公共类MyWordDocument{#region字段私有字符串文件名;私有XDocument文档;//todo:为所有可以包含占位符的文档xml文件创建字段privateDictionary>lookUpTable;#endregion#region属性publicIEnumerableTags{get{returnlookUpTable.Keys;}}#endregion#region构造publicMyWordDocument(stringfileName){this.fileName=fileName;提取文件();创建查找();}#endregion#region方法publicvoidReplaceTagWithValue(stringtagName,stringvalue){foreach(variteminlookUpTable[tagName]){item.Value=item.Value.Replace(string.Format(@"",tagName),value);}}publicvoidSave(stringfileName){document.Save(@"tempworddocument.xml");//todo:在此处保存文档的其他部分,即页脚页眉或其他内容ZipFile.CreateFromDirectory("temp",fileName);}privatevoidCreateLookUp(){//todo:使它适用于所有情况和所有可以包含占位符的文件//tip:打开原始文档inword并替换标签,//将文件保存到不同的位置并提取两个版本的xml文件并比较以查看您必须做什么lookUpTable=newDictionary>();正则表达式reg=newRegex(@".*)!??>");文档=XDocument.Load(@"tempworddocument.xml");XNamespacens=document.Root.GetNamespaceOfPrefix("w");IEnumerable元素=document.Root.Descendants(ns+"t").Where(NodeGotSplitUpIn2PartsDueToGrammarCheck).ToArray();foreach(variteminelements){XElementgrammar=item.Parent.PreviousNodeasXElement;语法.Remove();grammar=item.Parent.NextNode作为XElement;语法.Remove();XElementnext=(item.Parent.NextNodeasXElement).Element(ns+"t");stringtotalTagName=string.Format("{0}{1}",item.Value,next.Value);item.Parent.NextNode.Remove();item.Value=totalTagName;stringtagName=reg.Match(totalTagName).Groups["TagName"].Value;如果(lookUpTable.ContainsKey(tagName)){lookUpTable[tagName].Add(item);}else{厕所kUpTable.Add(tagName,newList{item});}}}privateboolNodeGotSplitUpIn2PartsDueToGrammarCheck(XElementnode){XNamespacens=node.Document.Root.GetNamespaceOfPrefix("w");returnnode.Value.StartsWith("并像这样使用它:classProgram{staticvoidMain(string[]args){MyWordDocumentdoc=newMyWordDocument("somedoc.docx");//todo:fixpathforeach(stringnameindoc.Tags)//name将是从占位符中提取的名称{doc.ReplaceTagWithValue(name,"Example");}doc.Save("output.docx");//todo:fixpath}}I有相同的需要,除了我想使用${...}条目而不是您可以自定义下面的代码以使用您的标签,但它需要更多状态。下面的代码适用于xml和openxml节点。我用xml测试了代码因为在word文档中,很难控制Word如何排列段落、行数和文本元素。我想这不是不可能,但这样我有更多的控制权:staticvoidMain(string[]args){//FillInValues(FileName("test01.docx"),FileName("test01_out.docx"));string[,]tests={{"${abc}${tha}","ABCTHA"},{"${abc}","ABC"},{"${abc}","ABC"},{"x${abc}","xABC"},{"x${abc}y","xABCy"},{"x${abc}${tha}z","xABCTHAz"},{"x${abc}u${tha}z","xABCuTHAz"},{"x${abc}u","xABCu"},{"x${abyupeekaiieic}u","xABYUPEEKAIIEICu"},{"x${abyupeekaiiei}","xABYUPEEKAIIEI"},};对于(inti=0;i{actualValue}=={expectedValue}={actualValue==expectedValue}");}Console.WriteLine("Done!");Console.ReadLine();}publicinterfaceITextReplacer{stringReplaceValue(字符串值);}publicclassDefaultTextReplacer:ITextReplacer{publicstringReplaceValue(stringvalue){return$"{value.ToUpper()}";}}publicinterfaceITextElement{stringValue{get;set;}voidRemoveFromParent();}publicclassXElementWrapper:ITextElement{privateXElement_element;publicXElementWrapper(XElement元素){_element=元素;}stringITextElement.Value{get{return_element.Value;}设置{_element.Value=值;}}publicXElementElement{get{return_element;}设置{_element=值;}}publicvoidRemoveFromParent(){_element.Remove();}}公共类OpenXmlTextWrapper:ITextElement{privateText_text;publicOpenXmlTextWrapper(Texttext){_text=text;}publicstringValue{get{return_text.Text;}设置{_text.Text=值;}}publicTextText{get{return_text;}设置{_text=值;}}publicvoidRemoveFromParent(){_text.Remove();}}privatestaticvoidFillInValues(stringsourceFileName,stringdestFileName){File.Copy(sourceFileName,destFileName,true);使用(WordprocessingDocumentdoc=WordprocessingDocument.Open(destFileName,true)){varbody=doc.MainDocumentPart.Document.Body;varparas=body.Descendants();SimpleStateMachinestateMachine=newSimpleStateMachine();//状态机ine.TextReplacer=ProcessParagraphs(paras,stateMachine);}}privatestaticvoidProcessParagraphs(IEnumerableparas,SimpleStateMachinestateMachine){foreach(varparainparas){foreach(varruninpara.Elements()){//Console.WriteLine("Newrun:");vartexts=run.Elements().ToArray();for(intk=0;k1$//0->0除了$//1->2{//1->0除了{//2->3}//2->2除了}//3->0publicITextReplacerTextReplacer{get;set;}=newDefaultTextReplacer();publicintState{get;set;}=0;publicListTextsList{get;}=newList();publicStringBuilderBuffer{get;}=newStringBuilder();//////在文本元素中找到$的索引///publicintPosition{get;set;}publicvoidReset(){State=0;TextsList.Clear();Buffer.Clear();}publicvoidAdd(ITextElementtext){if(TextsList.Count==0||TextsList.Last()!=text){TextsList.Add(text);}}}普blicvoidHandleText(ITextElementtext){//扫描字符for(inti=0;i!desc.Elements().Any())){XElementWrapperwrapper=newXElementWrapper(element);stateMachine.HandleText(包装器);}返回root.ToString(SaveOptions.DisableFormatting);我知道我的回答晚了,但可能对其他人有用也确保你测试它。明天我将对真实文件进行更多测试。如果我发现任何错误,我会在这里修复代码,但到目前为止一切顺利。更新:当${...}占位符放在表中时,代码不起作用。这是扫描文档的代码(FillInValues函数)有问题。更新:我更改了代码以扫描所有段落。以上就是《C#学习教程:OpenXML标签搜索与分享》的全部内容。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: