比较 Word 文档中的文本位置
Compare text locations in Word document
我通过用我的值替换模板文档中的一些占位符文本来生成 Word 文档。为此,我使用 GemBox.Document,更具体地说,Find and Replace 示例中的这段代码:
var document = DocumentModel.Load("input.docx");
var firstPlaceholder = document.Content.Find("%Text1%").First();
firstPlaceholder.LoadText("Value 1");
var secondPlaceholder = document.Content.Find("%Text2%").First();
firstPlaceholder.LoadText("Value 2");
document.Save("output.docx");
效果很好。
但现在我有一个场景,其中将替换占位符的值取决于它们的位置,更具体地说,占位符是出现在文档中某个特定段落之前还是之后。
我确实尝试过使用这样的东西:
Paragraph separator = ...
string firstPlaceholderText = "%Text1%";
string separatorText = seperator.Content.ToString();
string wholeDocumentText = document.Content.ToString();
if (wholeDocumentText.IndexOf(firstPlaceholderText) < wholeDocumentText.IndexOf(separatorText))
{
// The placeholder is before the separator...
}
else
{
// The placeholder is after the separator...
}
但是,相同的 separatorText
值可能出现在文档的多个位置,因此 string.IndexOf()
对我来说不是一个可行的解决方案。
有没有其他方法可以进行这种比较,或者有其他方法可以确定某些占位符与其他文档元素相比的位置?
试试这个:
static bool IsPositionBefore(ContentPosition position1, ContentPosition position2)
{
var parentIndexes1 = GetParentIndexes(position1.Parent);
var parentIndexes2 = GetParentIndexes(position2.Parent);
int count = Math.Min(parentIndexes1.Count, parentIndexes2.Count);
for (int i = 0; i < count; i++)
{
if (parentIndexes1[i] < parentIndexes2[i])
return true;
if (parentIndexes1[i] > parentIndexes2[i])
return false;
}
// Both positions are inside the same parent element.
var parent = position1.Parent;
var parentClone = parent.Clone(true);
string positionMarker1 = "\u0001";
string positionMarker2 = "\u0002";
position1.LoadText(positionMarker1);
position2.LoadText(positionMarker2);
string parentContent = parent.Content.ToString();
int positionOffset1 = parentContent.IndexOf(positionMarker1, StringComparison.Ordinal);
int positionOffset2 = parentContent.IndexOf(positionMarker2, StringComparison.Ordinal);
parent.Content.Set(parentClone.Content);
return positionOffset1 < positionOffset2;
}
static IList<int> GetParentIndexes(Element element)
{
var parentIndexes = new List<int>();
while (element.Parent != null)
{
parentIndexes.Add(element.ParentCollection.IndexOf(element));
element = element.Parent;
}
parentIndexes.Reverse();
return parentIndexes;
}
另外,下面是如何使用这个 IsPositionBefore
方法:
if (IsPositionBefore(firstPlaceholder.Start, separator.Content.Start))
{
// The placeholder is before the separator...
}
else
{
// The placeholder is after the separator...
}
棘手的部分是当两个位置都在同一元素内时如何确定哪个位置在前。
那是因为 ContentPosition
目前没有某种偏移量 API 可以告诉您它在元素中的确切位置。
所以,我正在做的是临时添加两个随机控制字符,检查哪个出现在另一个之前,然后删除它们。
我认为这种方法是安全的,因为 Word 文档不能包含控制字符(Word 应用程序会将它们显示为已损坏),如果您尝试保存包含此类字符的 DocumentModel
,则会出现异常。
我通过用我的值替换模板文档中的一些占位符文本来生成 Word 文档。为此,我使用 GemBox.Document,更具体地说,Find and Replace 示例中的这段代码:
var document = DocumentModel.Load("input.docx");
var firstPlaceholder = document.Content.Find("%Text1%").First();
firstPlaceholder.LoadText("Value 1");
var secondPlaceholder = document.Content.Find("%Text2%").First();
firstPlaceholder.LoadText("Value 2");
document.Save("output.docx");
效果很好。
但现在我有一个场景,其中将替换占位符的值取决于它们的位置,更具体地说,占位符是出现在文档中某个特定段落之前还是之后。
我确实尝试过使用这样的东西:
Paragraph separator = ...
string firstPlaceholderText = "%Text1%";
string separatorText = seperator.Content.ToString();
string wholeDocumentText = document.Content.ToString();
if (wholeDocumentText.IndexOf(firstPlaceholderText) < wholeDocumentText.IndexOf(separatorText))
{
// The placeholder is before the separator...
}
else
{
// The placeholder is after the separator...
}
但是,相同的 separatorText
值可能出现在文档的多个位置,因此 string.IndexOf()
对我来说不是一个可行的解决方案。
有没有其他方法可以进行这种比较,或者有其他方法可以确定某些占位符与其他文档元素相比的位置?
试试这个:
static bool IsPositionBefore(ContentPosition position1, ContentPosition position2)
{
var parentIndexes1 = GetParentIndexes(position1.Parent);
var parentIndexes2 = GetParentIndexes(position2.Parent);
int count = Math.Min(parentIndexes1.Count, parentIndexes2.Count);
for (int i = 0; i < count; i++)
{
if (parentIndexes1[i] < parentIndexes2[i])
return true;
if (parentIndexes1[i] > parentIndexes2[i])
return false;
}
// Both positions are inside the same parent element.
var parent = position1.Parent;
var parentClone = parent.Clone(true);
string positionMarker1 = "\u0001";
string positionMarker2 = "\u0002";
position1.LoadText(positionMarker1);
position2.LoadText(positionMarker2);
string parentContent = parent.Content.ToString();
int positionOffset1 = parentContent.IndexOf(positionMarker1, StringComparison.Ordinal);
int positionOffset2 = parentContent.IndexOf(positionMarker2, StringComparison.Ordinal);
parent.Content.Set(parentClone.Content);
return positionOffset1 < positionOffset2;
}
static IList<int> GetParentIndexes(Element element)
{
var parentIndexes = new List<int>();
while (element.Parent != null)
{
parentIndexes.Add(element.ParentCollection.IndexOf(element));
element = element.Parent;
}
parentIndexes.Reverse();
return parentIndexes;
}
另外,下面是如何使用这个 IsPositionBefore
方法:
if (IsPositionBefore(firstPlaceholder.Start, separator.Content.Start))
{
// The placeholder is before the separator...
}
else
{
// The placeholder is after the separator...
}
棘手的部分是当两个位置都在同一元素内时如何确定哪个位置在前。
那是因为 ContentPosition
目前没有某种偏移量 API 可以告诉您它在元素中的确切位置。
所以,我正在做的是临时添加两个随机控制字符,检查哪个出现在另一个之前,然后删除它们。
我认为这种方法是安全的,因为 Word 文档不能包含控制字符(Word 应用程序会将它们显示为已损坏),如果您尝试保存包含此类字符的 DocumentModel
,则会出现异常。