admin管理员组

文章数量:1333428

I am trying to manipulate numbering sequences in a Word document using the Open XML SDK. Specifically, I am working on updating the numbering for paragraphs that reference a NumberingInstance. However, I am encountering issues when updating the NumberID for specific paragraphs.

Problem Description:I have a set of paragraphs in a Word document, and I want to update their numbering properties. Each paragraph has a NumberingId which links it to a specific NumberingInstance. I am attempting to update the NumberID based on certain conditions, but the numbering is not updating correctly in some cases.It is changing numaric lists to bulleting and bulleting to numaric

I am using the following approach to update the NumberID:

private static List<(int SubTaskId, int OldNumberId, AbstractNum NewAbstractNum, NumberingInstance NewNumberingInstance)>
    GetAllNumberingInstancesWithUpdatedSubtaskSummaries(Dictionary<string, List<(int SubtaskId, List<Paragraph> Paragraphs, Numbering Numbering)>> rorReportDataContents)
{
    List<(int SubTaskId, int OldNumberId, AbstractNum NewAbstractNum, NumberingInstance NewNumberingInstance)> result = new();

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

                NumberingId numberingId = numberingProperties.Descendants<NumberingId>().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<string, List<(int subtaskId, List<Paragraph> paragraphs, Numbering numbering)>> rorReportDataContents, bool deleteMiscNote, bool deleteAmendmentNote)
{
    documentStream.Position = 0L;
    using WordprocessingDocument wordDoc = WordprocessingDocument.Open(documentStream, true);

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

    List<(Run Run, string Text)> 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<string, string> documentTags = [];
    runTexts.ForEach(x =>
    {
        MatchCollection matches = Regex.Matches(x.Text, "#([^#]*)#");
        foreach (Match match in matches.Cast<Match>())
        {
            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<string> extraDocumentTags = rorReportDataContents.Keys.Except(documentTags.Keys);
    List<Run> tobeRemovedRuns = runTexts.Where(x => extraDocumentTags.Contains(x.Text)).Select(x => x.Run).ToList();
    tobeRemovedRuns.ForEach(run => run.Remove());
    DeleteMiscAndAmendmentNoteSection(runs, deleteMiscNote, deleteAmendmentNote);
    KeyValuePair<string, string> miscTag = RoRReportMasterTags.TagNameSyntaxPair.First(x => x.Key == RoRReportMasterTagNameConstants.MiscSection);

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

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

    List<(int SubTaskId, int oldNumberId, AbstractNum newAbstractNum, NumberingInstance newNumberingInstance)> 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<string, List<(int subtaskId, List<Paragraph> paragraphs, Numbering numbering)>> item in rorReportDataContents)
    {
        Paragraph originalParagraph = paragraphs.Find(x => x.InnerText.Contains(item.Key.Replace("#", string.Empty)));
        List<string> 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<ParagraphProperties>().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<Paragraph> paragraphs, Numbering numbering) content in item.Value)
                {
                    foreach (Paragraph paragraph in content.paragraphs)
                    {
                        _ = paragraph.Parent?.RemoveChild(paragraph);

                        NumberingProperties numberingProperties = paragraph.ParagraphProperties?.Descendants<NumberingProperties>().FirstOrDefault();
                        NumberingId numberingId = numberingProperties?.Descendants<NumberingId>().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<NumberingProperties>().First().Descendants<NumberingId>().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()
    };
}

本文标签: