Проблема с обновлением нумерации и маркировки в документе Word с использованием Open XML SDK (назначение NumberID)C#

Место общения программистов C#
Ответить
Anonymous
 Проблема с обновлением нумерации и маркировки в документе Word с использованием Open XML SDK (назначение NumberID)

Сообщение Anonymous »

Я пытаюсь манипулировать последовательностями нумерации в документе Word с помощью Open XML SDK. В частности, я работаю над обновлением нумерации абзацев, ссылающихся на NumberingInstance. Однако я сталкиваюсь с проблемами при обновлении NumberID для определенных абзацев.
Описание проблемы. У меня есть набор абзацев в документе Word, и я хочу обновить их свойства нумерации. Каждый абзац имеет NumberingId, который связывает его с определенным экземпляром NumberingInstance. Я пытаюсь обновить NumberID на основе определенных условий, но в некоторых случаях нумерация не обновляется правильно. Числовые списки заменяются на маркированные, а маркированные на числовые.
Я использую следующее подход к обновлению NumberID:
private static List
GetAllNumberingInstancesWithUpdatedSubtaskSummaries(Dictionary rorReportDataContents)
{
List result = new();

foreach (var content in rorReportDataContents)
{
foreach (var item in content.Value.Where(x => x.Numbering is not null))
{
List abstractNumList = item.Numbering.Descendants().ToList();
List numberingInstances = item.Numbering.Descendants().ToList();
List groupedData = (from abstractNum in abstractNumList
join numbering in numberingInstances
on abstractNum.AbstractNumberId equals numbering.AbstractNumId.Val
select (abstractNum, numbering)).ToList();
List paragraphs = item.Paragraphs.Where(x => x.ParagraphProperties is not null).ToList();
foreach (var paragraph in paragraphs)
{
NumberingProperties numberingProperties = paragraph.ParagraphProperties.Descendants().FirstOrDefault();
if (numberingProperties is null) continue;

NumberingId numberingId = numberingProperties.Descendants().FirstOrDefault();
if (numberingId is null) continue;

int numberingValue = numberingId.Val;
if (!result.Exists(x => x.SubTaskId == item.SubtaskId && x.OldNumberId == numberingValue))
{
var numbering = groupedData.Find(x => x.NumberingInstance.NumberID == numberingValue);
if (numbering.AbstractNum != null && numbering.NumberingInstance != null)
{
numbering.AbstractNum.AbstractNumberId = result.Count + 1;
numbering.NumberingInstance.AbstractNumId.Val = result.Count + 1;
numbering.NumberingInstance.NumberID = result.Count + 1;
numbering.AbstractNum.Parent?.RemoveAllChildren();
numbering.NumberingInstance.Parent?.RemoveAllChildren();
result.Add((item.SubtaskId, OldNumberId: numberingValue, numbering.AbstractNum, numbering.NumberingInstance));
}
}
}
}
}

return result;
}
public MemoryStream ReplaceRorReportContents(MemoryStream documentStream, Dictionary rorReportDataContents, bool deleteMiscNote, bool deleteAmendmentNote)
{
documentStream.Position = 0L;
using WordprocessingDocument wordDoc = WordprocessingDocument.Open(documentStream, true);

MainDocumentPart mainPart = wordDoc.MainDocumentPart;
List runs = mainPart.Document.Body.Descendants().ToList();
List paragraphs = mainPart.RootElement.Descendants().Where(x => !string.IsNullOrEmpty(x.InnerText)).ToList();

List runTexts = runs.Where(x => x.RunProperties is not null
&& x.RunProperties.Bold is not null
&& !string.IsNullOrEmpty(x.InnerText)
&& x.InnerText.Contains('#')).Select(x => (x, x.InnerText)).ToList();
Dictionary documentTags = [];
runTexts.ForEach(x =>
{
MatchCollection matches = Regex.Matches(x.Text, "#([^#]*)#");
foreach (Match match in matches.Cast())
{
string matchValue = match.Groups[0].Value;
if (matchValue.Contains('$'))
{
int startIndex = matchValue.IndexOf('$');
int lastIndex = matchValue.LastIndexOf('#');
string stylingProperties = matchValue[startIndex..lastIndex];
string docTag = matchValue.Replace(stylingProperties, string.Empty);
_ = x.Text.Replace(matchValue, docTag);
_ = documentTags.TryAdd(docTag, stylingProperties.Replace("$", string.Empty));
}
else
{
_ = documentTags.TryAdd(matchValue, string.Empty);
}
}
});

IEnumerable extraDocumentTags = rorReportDataContents.Keys.Except(documentTags.Keys);
List tobeRemovedRuns = runTexts.Where(x => extraDocumentTags.Contains(x.Text)).Select(x => x.Run).ToList();
tobeRemovedRuns.ForEach(run => run.Remove());
DeleteMiscAndAmendmentNoteSection(runs, deleteMiscNote, deleteAmendmentNote);
KeyValuePair miscTag = RoRReportMasterTags.TagNameSyntaxPair.First(x => x.Key == RoRReportMasterTagNameConstants.MiscSection);

IEnumerable parts = wordDoc.GetAllParts();
NumberingDefinitionsPart numberingPart = parts.OfType().FirstOrDefault();

numberingPart ??= wordDoc.MainDocumentPart.AddNewPart();
numberingPart.Numbering ??= new Numbering();

List numberingInstances = GetAllNumberingInstancesWithUpdatedSubtaskSummaries(rorReportDataContents);

foreach (var numberingInstance in numberingInstances)
{
numberingInstance.newAbstractNum.Parent?.RemoveAllChildren();
numberingInstance.newNumberingInstance.Parent?.RemoveAllChildren();
numberingPart.Numbering.Append(numberingInstance.newAbstractNum, numberingInstance.newNumberingInstance);
}

NumberingFormat miscNumberingFormat = GetNumberingFormat(documentTags.GetValueOrDefault(miscTag.Value));
int lastAbstractNumId = numberingInstances.Count != 0 ? numberingInstances.Max(x => x.newAbstractNum.AbstractNumberId) : 0;
int miscAbstractNumId = lastAbstractNumId + 1;
(AbstractNum miscAbstractNum, NumberingInstance miscNumberingInstance) = CreateAbstractNumberingDefinition(miscNumberingFormat, miscAbstractNumId);

numberingPart.Numbering.Append(miscAbstractNum, miscNumberingInstance);

foreach (KeyValuePair item in rorReportDataContents)
{
Paragraph originalParagraph = paragraphs.Find(x => x.InnerText.Contains(item.Key.Replace("#", string.Empty)));
List texts = paragraphs.Select(x => x.InnerText).ToList();
if (originalParagraph is not null)
{
Paragraph currentElement = originalParagraph;
if (originalParagraph.InnerText.Contains(miscTag.Value.Replace("#", string.Empty)))
{
originalParagraph.RemoveAllChildren();
foreach (Paragraph paragraph in item.Value.SelectMany(x => x.paragraphs))
{
_ = paragraph.Parent?.RemoveChild(paragraph);
ParagraphProperties paragraphProperties = paragraph.Descendants().OfType().FirstOrDefault();
// Adjust line spacing for paragraphs with bullets
//if (HasBullets(paragraph))
//{

//}
_ = paragraphProperties is null
? paragraph.AddChild(new ParagraphProperties(new NumberingProperties(
new NumberingLevelReference { Val = 0 },
new NumberingId { Val = miscAbstractNumId }
)))
: paragraph.ParagraphProperties.AddChild(new NumberingProperties(
new NumberingLevelReference { Val = 0 },
new NumberingId { Val = miscAbstractNumId }
));
//AdjustLineSpacing(paragraph);

Paragraph insteredElement = currentElement.InsertAfterSelf(paragraph);
currentElement = insteredElement;
}
}
else
{
originalParagraph.RemoveAllChildren();
foreach ((int subtaskId, List paragraphs, Numbering numbering) content in item.Value)
{
foreach (Paragraph paragraph in content.paragraphs)
{
_ = paragraph.Parent?.RemoveChild(paragraph);

NumberingProperties numberingProperties = paragraph.ParagraphProperties?.Descendants().FirstOrDefault();
NumberingId numberingId = numberingProperties?.Descendants().FirstOrDefault();

if (numberingId is not null)
{
int numberId = numberingId.Val;
//int newNumberingId = numberingInstances.First(x => x.SubTaskId == content.subtaskId
// && x.oldNumberId == numberId)
// .newNumberingInstance.NumberID;
var matchingInstance = numberingInstances.FirstOrDefault(x => x.SubTaskId == content.subtaskId
&& x.oldNumberId == numberId);
if (matchingInstance.SubTaskId != 0)
{
int newNumberingId = matchingInstance.newNumberingInstance.NumberID;
// Use newNumberingId as needed
paragraph.ParagraphProperties.Descendants().First().Descendants().First().Val = newNumberingId;
}
//else
//{

//}
}

Paragraph insteredElement = currentElement.InsertAfterSelf(paragraph);
currentElement = insteredElement;
}
}
}

originalParagraph.Remove();
}

mainPart.Document.Save();
}

documentStream.Position = 0L;

return documentStream;
}
private static (AbstractNum abstractNum, NumberingInstance numberingInstance) CreateAbstractNumberingDefinition(NumberingFormat numberingFormat, int abstractNumId)
{
AbstractNum abstractNum = new(
new Level(
// StartNumberingValue indicates the starting value of the numbering
new StartNumberingValue { Val = 1 },
new LevelJustification { Val = LevelJustificationValues.Center },
// NumberingFormat specifies the numbering format (e.g., decimal, lowerLetter)
numberingFormat,
// LevelText defines the level text (e.g., "%1." for decimal numbering)
new LevelText { Val = "%1•" },
//new Indentation { Left = "0"},
new NumberingSymbolRunProperties
{
Bold = new Bold(),
FontSize = new FontSize() { Val = "25" }
//Spacing = new Spacing { Val = 10},
//Position = new Position { Val = "5" },

},
new ParagraphProperties(
new Indentation { Left = "720", Hanging = "360" }
),
new SpacingBetweenLines { LineRule = LineSpacingRuleValues.Exact }

)

{ LevelIndex = 0 }
)
{ AbstractNumberId = abstractNumId };

NumberingInstance numberingInstance = new(
new AbstractNumId { Val = abstractNum.AbstractNumberId }
)
{ NumberID = abstractNum.AbstractNumberId };

return (abstractNum, numberingInstance);
}
private static NumberingFormat GetNumberingFormat(string numberingTypeValue)
{
_ = Enum.TryParse(numberingTypeValue, true, out NumberingType numberingType);
return numberingType switch
{
NumberingType.None => new NumberingFormat { Val = NumberFormatValues.None },
NumberingType.Bullets => new NumberingFormat { Val = NumberFormatValues.Bullet },
NumberingType.Numeric => new NumberingFormat { Val = NumberFormatValues.Decimal },
NumberingType.LowerAlphabetical => new NumberingFormat { Val = NumberFormatValues.LowerLetter },
NumberingType.UpperAlphabetical => new NumberingFormat { Val = NumberFormatValues.UpperLetter },
_ => throw new NotImplementedException()
};
}


Подробнее здесь: https://stackoverflow.com/questions/792 ... en-xml-sdk
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»