.net 用word文档中的特定样式替换文本并不适用于所有OpenXmlPart:s
我试图替换存储在数据库中的Word文档中的一组“字段”。“字段”实际上只是用一种样式(我相信它在Word中被称为Quick style)格式化的文本,并带有我们选择的特定名称 此类适用于所有页眉部分和页脚部分,但由于某些原因,它不适用于正文(MainDocumentPart)。调试时,我可以看到样式出现在正文中,就像它们出现在页眉和页脚部分一样,并且插入了文本,但是当我随后检查Word文档时,只有页眉和页脚被更新。正文仍然包含旧值 Word文档中的XML可能如下所示:.net 用word文档中的特定样式替换文本并不适用于所有OpenXmlPart:s,.net,vb.net,openxml,openxml-sdk,.net,Vb.net,Openxml,Openxml Sdk,我试图替换存储在数据库中的Word文档中的一组“字段”。“字段”实际上只是用一种样式(我相信它在Word中被称为Quick style)格式化的文本,并带有我们选择的特定名称 此类适用于所有页眉部分和页脚部分,但由于某些原因,它不适用于正文(MainDocumentPart)。调试时,我可以看到样式出现在正文中,就像它们出现在页眉和页脚部分一样,并且插入了文本,但是当我随后检查Word文档时,只有页眉和页脚被更新。正文仍然包含旧值 Word文档中的XML可能如下所示: <w:p w:r
<w:p w:rsidR="00394599" w:rsidRPr="00162F1F" w:rsidRDefault="00394599" w:rsidP="000663BC">
<w:pPr>
<w:pStyle w:val="NovaIssuedBy"/>
</w:pPr>
<w:r>
<w:t>NovaIssuedBy</w:t>
</w:r>
</w:p>
新发行人
当然,应该替换w:t元素中的文本NovaIssuedBy,正如我所说的,这段代码适用于页眉和页脚中类似的“字段”
子UpdateNOVAFieldsInternal遍历文档中的所有部分(我认为),包括所有的页眉、正文和页脚。如果每个零件(在此函数中称为节)包含某些样式,则会对其进行检查,如果需要,会替换文本
子检查部分检查我们预定义的所有样式,并在需要时替换文本
子FindStyleReplaceTextInstruction发挥了神奇的作用,它找到所有标记有样式StyleName的部分,并用参数文本中的文本替换它们
有人知道为什么这段代码适用于页眉和页脚部分,但不适用于正文(MainDocumentPart)?有没有人能比我们在这个解决方案中使用样式和样式名更好地解决在Word文档的特定位置更新某些文本的“问题”(不仅仅是一次,而是多次)呢
Option Strict On
Option Infer On
Imports Nova.Datasets
Imports DocumentFormat.OpenXml.Packaging
Imports DocumentFormat.OpenXml.Wordprocessing
Imports DocumentFormat.OpenXml
Imports System.Collections.Generic
Imports System.Xml
Imports System.IO
Imports System.Text
Imports System.Xml.Linq
Imports System.Linq
Imports <xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
Public Class NovaFields
Private m_Document As EmptyDocument.Data_DocumentRow = Nothing
Private m_Data As Byte()
Public Sub New(ByRef document As EmptyDocument.Data_DocumentRow)
m_Document = document
With m_Document
If Not .FileExtension.ToUpper() = "DOCX" Then
'Exception!
'This is not a DOCX file!
Throw New ApplicationException("This is not a DOCX file!")
End If
m_Data = .FileData
End With
End Sub
Public Sub UpdateNOVAFields(ByVal parameters As NovaParameters)
UpdateNOVAFieldsInternal(parameters)
m_Document.FileData = m_Data
End Sub
''' <summary>
''' This will replace all "fields" that are set in parameters in the document in m_data
''' </summary>
''' <param name="parameters"></param>
''' <remarks></remarks>
Private Sub UpdateNOVAFieldsInternal(ByVal parameters As NovaParameters)
Using documentStream As New MemoryStream()
' Read all the bytes, except the last Zero-byte that "closes the file", hence the -1
documentStream.Write(m_Data, 0, m_Data.Length - 1)
Using document As WordprocessingDocument = WordprocessingDocument.Open(documentStream, True)
' Assign a reference to the existing document body.
Dim body As Body = document.MainDocumentPart.Document.Body
Dim headerPart As OpenXmlPart
Dim footerPart As OpenXmlPart
' Check each Header-part
For Each headerPart In document.MainDocumentPart.HeaderParts
CheckSection(parameters, headerPart)
Next headerPart
' Check the Body-part
CheckSection(parameters, document.MainDocumentPart)
' Check each Footer-part
For Each footerPart In document.MainDocumentPart.FooterParts
CheckSection(parameters, footerPart)
Next footerPart
' Close and save the document
document.Close()
End Using
' We must add an extra Zero-byte at the end of the stream to "close the file"
documentStream.Position = documentStream.Length
documentStream.WriteByte(0)
m_Data = documentStream.ToArray()
End Using
End Sub
''' <summary>
''' Check the section provided for all parameters(styles)
''' </summary>
''' <param name="parameters">The parameters to use</param>
''' <param name="section">The section to check</param>
''' <remarks></remarks>
Private Sub CheckSection(parameters As NovaParameters, ByRef section As OpenXmlPart)
' A bunch of if-statements like the one below are removed just to shorten the text
' IssuedBy
If (parameters.IssuedBySet) Then
FindStyleReplaceTextInSection(parameters.IssuedByStyleName, parameters.IssuedBy, section)
End If
End Sub
''' <summary>
''' This function will replace the text in a section formatted with a style called styleName in the section provided
''' </summary>
''' <param name="styleName">The name of the style to replace the text in</param>
''' <param name="text">The new text that will be replacing the old text in the document</param>
''' <param name="section">The section to scan for a style with the name styleName</param>
''' <remarks></remarks>
Private Sub FindStyleReplaceTextInSection(styleName As String, text As String, ByRef section As OpenXmlPart)
Try
Dim xDoc As XDocument = XDocument.Load(XmlReader.Create(section.GetStream()))
' Get all Style elements with an attribute that starts with styleName (sometimes Word adds "Char" after the style name)
Dim foundStyles As IEnumerable(Of XElement) = _
From element In xDoc.Root.Descendants() _
Where Not String.IsNullOrEmpty(element.@w:val) AndAlso element.@w:val.StartsWith(styleName) _
Select element
Dim w As XNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
For Each item In foundStyles
' Get the Style-elements parents parent
Dim parent As XElement = item.Parent.Parent
' Check if it is a Run element or Paragraph element
If parent.Name.LocalName = "r" Then
' Run
' Remove old text elements
parent...<w:t>.Remove()
' Add a new text element with the text provided
parent.Add(<w:t><%= text %></w:t>)
Else
' Paragraph, has an extra layer around the Run element
' Remove old text elements
parent...<w:t>.Remove()
' Tried different ways of doing it here
' First way of doing it, seems to work only for Header and Footer
Dim run As XElement = parent.Element(w + "r")
run.Add(<w:t><%= text %></w:t>)
' Second way of doing it, this works too for Header and Footer
'parent.<w:r>.FirstOrDefault().Add(<w:t><%= text %></w:t>)
End If
Next
' Save the XML into the package.
Using writer As XmlWriter = XmlWriter.Create(section.GetStream(FileMode.Create, FileAccess.Write))
xDoc.Save(writer)
End Using
Catch ex As Exception
Debug.Print("Error in FindStyleReplaceTextInSection!")
End Try
End Sub
End Class
选项严格打开
选项推断
导入Nova.dataset
导入DocumentFormat.OpenXml.Packaging
导入DocumentFormat.OpenXml.Wordprocessing
导入DocumentFormat.OpenXml
导入System.Collections.Generic
导入System.Xml
导入System.IO
导入系统文本
导入System.Xml.Linq
导入系统
进口
公共类字段
私有m_文档为EmptyDocument.Data_DocumentRow=无
专用m_数据作为字节()
Public Sub New(ByRef文档作为EmptyDocument.Data\u DocumentRow)
m_文件=文件
带m_文件
如果不是。FileExtension.ToUpper()=“DOCX”,则
“例外!
'这不是DOCX文件!
抛出新的ApplicationException(“这不是DOCX文件!”)
如果结束
m_Data=.FileData
以
端接头
公共子UpdateNOVAFields(ByVal参数作为NovaParameters)
UpdateNOVAFieldsInternal(参数)
m_Document.FileData=m_数据
端接头
'''
''这将替换m_数据中文档参数中设置的所有“字段”
'''
'''
'''
私有子更新NovaFieldsInternal(ByVal参数作为NovaParameters)
将documentStream用作新的MemoryStream()
'读取所有字节,但最后一个“关闭文件”的零字节除外,因此为-1
documentStream.Write(m_Data,0,m_Data.Length-1)
将文档用作WordprocessingDocument=WordprocessingDocument.Open(documentStream,True)
'指定对现有文档正文的引用。
将主体尺寸标注为主体=document.main documentpart.document.body
作为OpenXmlPart的Dim headerPart
将footerPart设置为OpenXmlPart
'检查每个标题部分
对于document.main documentpart.headerPart中的每个headerPart
检查部分(参数,标题部分)
下一任校长
“检查身体部位
检查部分(参数,document.MainDocumentPart)
'检查每个页脚部分
对于document.MainDocumentPart.FooterParts中的每个footerPart
检查部分(参数、页脚部分)
下一部分
'关闭并保存文档
文件关闭()
终端使用
'我们必须在流的末尾添加额外的零字节以“关闭文件”
documentStream.Position=documentStream.Length
documentStream.WriteByte(0)
m_Data=documentStream.ToArray()
终端使用
端接头
'''
''检查为所有参数(样式)提供的部分
'''
''要使用的参数
''要检查的部分
'''
私有子CheckSection(参数作为NovaParameters,ByRef节作为OpenXmlPart)
“删除一堆类似下面的if语句只是为了缩短文本
"发布人:
如果(parameters.IssuedBySet),则
FindStyleReplaceTextInSection(parameters.IssuedByStyleName、parameters.IssuedBy、section)
如果结束
端接头
'''
''此函数将在提供的节中用名为styleName的样式替换格式化节中的文本
'''
''要替换中文本的样式的名称
''将替换文档中旧文本的新文本
''用于扫描名为styleName的样式的部分
'''
私有子FindStyleReplaceTextInSection(样式名为字符串,文本为字符串,ByRef节为OpenXmlPart)
尝试
Dim xDoc As XDocument=XDocument.Load(XmlReader.Create(section.GetStream()))
'使用以styleName开头的属性获取所有样式元素(有时Word会在样式名称后添加“Char”)
将foundStyles设置为IEnumerable(属于XElement)=_
xDoc.Root.subjects()中的From元素_
Where Not String.IsNullOrEmpty(元素@w:val)和also元素@w:val.StartsWit
' Check the Body-part
CheckSection(parameters, document.MainDocumentPart)
' Check each Header-part
For Each headerPart In document.MainDocumentPart.HeaderParts
CheckSection(parameters, headerPart)
Next headerPart
' Check each Footer-part
For Each footerPart In document.MainDocumentPart.FooterParts
CheckSection(parameters, footerPart)
Next footerPart