Freigeben über


Anwenden einer Formatvorlage auf einen Absatz in einem Dokument aus einem Textverarbeitungsprogramm

In diesem Thema wird gezeigt, wie Sie die Klassen im Open XML SDK für Office verwenden, um eine Formatvorlage programmgesteuert auf einen Absatz in einem Textverarbeitungsdokument anzuwenden. Es enthält eine ApplyStyleToParagraph -Beispielmethode, um diese Aufgabe zu veranschaulichen, sowie mehrere zusätzliche Beispielmethoden zum Überprüfen, ob eine Formatvorlage vorhanden ist, zum Hinzufügen einer neuen Formatvorlage und zum Hinzufügen des Formatvorlagenteils.

ApplyStyleToParagraph-Methode

Die ApplyStyleToParagraph -Beispielmethode kann verwendet werden, um eine Formatvorlage auf einen Absatz anzuwenden. Sie müssen zunächst einen Verweis auf das Dokument sowie einen Verweis auf den zu formatierenden Absatz abrufen. Die Methode akzeptiert vier Parameter, die Folgendes angeben: der Verweis auf das geöffnete Dokument aus dem Textverarbeitungsprogramm, die Formatvorlagen-ID der anzuwendenden Formatvorlage, den Namen der anzuwendenden Formatvorlage und der Verweis auf den Absatz, auf den die Formatvorlage angewendet werden soll.

    public static void ApplyStyleToParagraph(WordprocessingDocument doc, string styleid, string stylename, Paragraph p)

In den folgenden Abschnitten in diesem Thema werden die Implementierung dieser Methode und der unterstützende Code sowie deren Aufruf erläutert. Den vollständigen Beispielcodeeintrag finden Sie im Abschnitt Beispielcode am Ende dieses Themas.

Abrufen eines WordprocessingDocument-Objekts

Im Abschnitt "Beispielcode" ist auch der Code dargestellt, der zum Einrichten des Aufrufs der Beispielmethode erforderlich ist. Wenn Sie die Methode zum Anwenden einer Formatvorlage auf einen Absatz in einem Dokument verwenden möchten, benötigen Sie zuerst einen Verweis auf das geöffnete Dokument. Im Open XML SDK stellt die WordprocessingDocument -Klasse ein Word-Dokumentpaket dar. Zum Öffnen und Bearbeiten eines Word-Dokuments müssen Sie anhand des Dokuments eine Instanz der WordprocessingDocument-Klasse erstellen. Nachdem Sie die instance erstellt haben, verwenden Sie ihn, um Zugriff auf den Standard Dokumentteil zu erhalten, der den Text des Dokuments enthält. Der Inhalt des Hauptdokumentteils ist im Paket mithilfe des WordprocessingML-Markups als XML dargestellt.

Um die Klasse instance zu erstellen, rufen Sie eine der Überladungen der Open()-Methode auf. Der folgende Beispielcode zeigt die Verwendung der WordprocessingDocument.Open-Überladung. Der erste Parameter ist eine Zeichenfolge, die den vollständigen Pfad des zu öffnenden Dokuments darstellt. Der zweite Parameter enthält den Wert true oder false und gibt an, ob die Datei zur Bearbeitung geöffnet werden soll. In diesem Beispiel lautet der Parameter true, um den Lese-/Schreibzugriff auf die Datei zu aktivieren.

    using (WordprocessingDocument doc = 
        WordprocessingDocument.Open(fileName, true))
    {
       // Code removed here. 
    }

Struktur eines WordProcessingML-Dokuments

Die grundlegende Struktur eines WordProcessingML-Dokuments besteht aus den document- und body-Elementen, gefolgt von einem oder mehreren Block-Level-Elementen wie p, das für einen Absatz steht. Ein Absatz enthält ein oder mehrere r-Elemente. r steht für ausführen und meint einen Textbereich mit gemeinsamen Eigenschaften wie Formatierung. Eine Ausführung besteht aus einem oder mehreren t-Elementen. Das t-Element enthält einen Textbereich. Das folgende Codebeispiel zeigt das WordprocessingML-Markup für ein Dokument, das den Text "Beispieltext" enthält.

    <w:document xmlns:w="https://schemas.openxmlformats.org/wordprocessingml/2006/main">
      <w:body>
        <w:p>
          <w:r>
            <w:t>Example text.</w:t>
          </w:r>
        </w:p>
      </w:body>
    </w:document>

Mit dem Open XML SDK können Sie Dokumentstrukturen und -inhalte mit stark typisierten Klassen erstellen, die WordprocessingML-Elementen entsprechen. Diese Klassen sind im DocumentFormat.OpenXml.Wordprocessing -Namespace enthalten. Die folgende Tabelle enthält die Namen der Klassen, die den Elementen document, body, p, r und t entsprechen.

WordprocessingML-Element Open XML SDK-Klasse Beschreibung
document Document Das Stammelement des Hauptdokumentteils.
Text Body Der Container für die Strukturen auf Blockebene, z. B. Absätze, Tabellen, Anmerkungen und andere, die in der Spezifikation ISO/IEC 29500 angegeben sind.
p Paragraph Ein Absatz.
r Run Ein Lauf.
t Text Ein Textbereich.

Weitere Informationen zur Gesamtstruktur der Teile und Elemente eines WordprocessingML-Dokuments finden Sie unter Struktur eines WordprocessingML-Dokuments.

Abrufen des Absatzes in formatieren

Nach dem Öffnen der Datei ruft der Code einen Verweis auf den ersten Absatz ab. Da ein typisches Dokument aus einem Textverarbeitungsprogramm im Textkörper viele Arten von Elementen enthält, filtert der Code die Nachfolger im Textkörper des Dokuments, die den Typ Paragraph aufweisen. DieElementAtOrDefault-Methode wird dann verwendet, um einen Verweis auf den Absatz abzurufen. Da die Elemente beginnend mit 0 (null) indiziert werden, übergeben Sie eine 0 (null), um den Verweis auf den ersten Absatz abrufen, wie im folgenden Beispiel gezeigt wird.

    // Get the first paragraph.
    Paragraph p =
      doc.MainDocumentPart.Document.Body.Descendants<Paragraph>()
      .ElementAtOrDefault(0);

    // Check for a null reference. 
    if (p == null)
    {
        // Code removed here…
    }

Der Verweis auf den gefundenen Absatz wird in einer Variablen mit dem Namen "p" gespeichert. Wenn ein Absatz am angegebenen Index nicht gefunden wird, gibt die ElementAtOrDefault-Methode als Standardwert NULL zurück. Dies bietet die Möglichkeit, auf NULL zu testen und einen Fehler mit einer entsprechenden Fehlermeldung auszulösen.

Sobald Sie die Verweise auf das Dokument und den Absatz haben, können Sie die ApplyStyleToParagraph-Beispielmethode aufrufen, um die verbleibende Arbeit zu erledigen. Zum Aufrufen der Methode übergeben Sie den Verweis auf das Dokument als ersten Parameter, die Formatvorlagen-ID der anzuwendenden Formatvorlage als zweiten Parameter, den Namen der Formatvorlage als dritten Parameter und den Verweis auf den Absatz, auf den die Formatvorlage angewendet werden soll, als vierten Parameter.

Hinzufügen des Absatzeigenschaftenelements

Der erste Schritt der Beispielmethode besteht im Sicherstellen, dass der Absatz ein Absatzeigenschaftenelement enthält. Das Absatzeigenschaftenelement ist ein untergeordnetes Element des Absatzes und enthält eine Reihe von Eigenschaften, mit denen Sie die Formatierung des Absatzes angeben.

Mit den folgenden Informationen aus der Spezifikation ISO/IEC 29500 wird das pPr-Element (Absatzeigenschaften) zum Angeben der Formatierung eines Absatzes eingeführt. Beachten Sie, dass alle Abschnittsnummern, denen ein § vorangestellt ist, aus der ISO-Spezifikation stammen.

Innerhalb des Absatzes sind alle Rich-Formatierungen auf Absatzebene im pPr -Element gespeichert (§17.3.1.25; §17.3.1.26). [Hinweis: Bei einigen Beispielen für Absatzeigenschaften handelt es sich um Ausrichtung, Rahmen, Außerkraftsetzung der Silbentrennung, Einzug, Zeilenabstand, Schattierung, Textrichtung und Steuerelemente für Absatzkontrolle.

Zwischen den Eigenschaften befindet sich das pStyle-Element zum Angeben der auf den Absatz anzuwendenden Formatvorlage. Das folgende Beispielmarkup zeigt beispielsweise ein pStyle-Element, das die Formatvorlage "OverdueAmount" angibt.

    <w:p  xmlns:w="https://schemas.openxmlformats.org/wordprocessingml/2006/main">
      <w:pPr>
        <w:pStyle w:val="OverdueAmount" />
      </w:pPr>
      ... 
    </w:p>

Im Open XML SDK wird das pPr-Element durch die ParagraphProperties-Klasse dargestellt. Der Code bestimmt, ob das Element vorhanden ist, und erstellt eine neue Instanz der ParagraphProperties-Klasse, wenn dies nicht der Fall ist. Das pPr-Element ist ein untergeordnetes Element des p-Elements (paragraph). Aus diesem Grund wird die PrependChild<T>(T)-Methode verwendet, um die Instanz hinzuzufügen, wie im folgenden Codebeispiel gezeigt.

    // If the paragraph has no ParagraphProperties object, create one.
    if (p.Elements<ParagraphProperties>().Count() == 0)
    {
        p.PrependChild<ParagraphProperties>(new ParagraphProperties());
    }

    // Get the paragraph properties element of the paragraph.
    ParagraphProperties pPr = p.Elements<ParagraphProperties>().First();

Hinzufügen des Teils "Formatvorlagen"

Wenn der gefundene Absatz und das Absatzeigenschaftenelement vorhanden sind, stellen Sie jetzt sicher, dass die Voraussetzungen für die Anwendung der Formatvorlage erfüllt sind. Formatvorlagen in WordprocessingML werden in einem eigenen eindeutigen Teil gespeichert. Obwohl es in der Regel richtig ist, dass sowohl der Teil als auch eine Reihe von Basisformatvorlagen automatisch erstellt werden, wenn Sie das Dokument mithilfe einer Anwendung wie Microsoft Word erstellen, ist der Formatvorlagenteil nicht erforderlich, damit ein Dokument als gültig angesehen wird. Wenn Sie das Dokument programmgesteuert mit dem Open XML SDK erstellen, wird der Formatvorlagenteil nicht automatisch erstellt. sie müssen explizit erstellt werden. Folglich überprüft der folgende Code, ob der Formatvorlagenteil vorhanden ist, und erstellt ihn, wenn dies nicht der Fall ist.

    // Get the Styles part for this document.
    StyleDefinitionsPart part =
        doc.MainDocumentPart.StyleDefinitionsPart;

    // If the Styles part does not exist, add it and then add the style.
    if (part == null)
    {
        part = AddStylesPartToPackage(doc);
        // Code removed here...
    }

Die AddStylesPartToPackage-Beispielmethode fügt den Formatvorlagenteil hinzu. Sie erstellt einen Teil vom Typ StyleDefinitionsPart und fügt ihn dem Hauptdokumentteil als untergeordneten Teil hinzu. Der Code fügt dann das Styles-Stammelement hinzu, welches das übergeordnete Element ist, das alle Formatvorlagen enthält. Das Styles-Element wird durch die Styles-Klasse im Open XML SDK dargestellt. Schließlich speichert der Code das Teil.

    // Add a StylesDefinitionsPart to the document.  Returns a reference to it.
    public static StyleDefinitionsPart AddStylesPartToPackage(WordprocessingDocument doc)
    {
        StyleDefinitionsPart part;
        part = doc.MainDocumentPart.AddNewPart<StyleDefinitionsPart>();
        Styles root = new Styles();
        root.Save(part);
        return part;
    }

Überprüfen, ob die Formatvorlage vorhanden ist

Das Anwenden einer Formatvorlage, die nicht vorhanden ist, auf einen Absatz hat keine Auswirkungen. es wird keine Ausnahme generiert, und es treten keine Formatierungsänderungen auf. Der Beispielcode überprüft, ob die Formatvorlage vorhanden ist, bevor versucht wird, die Formatvorlage anzuwenden. Formatvorlagen werden im Formatvorlagenteil gespeichert. Wenn der Formatvorlagenteil also nicht vorhanden ist, kann die Formatvorlage selbst nicht vorhanden sein.

Wenn der Formatvorlagenteil vorhanden ist, sucht der Code nach einer passenden Formatvorlage, indem er die IsStyleIdInDocument-Beispielmethode aufruft und das Dokument und die Formatvorlagen-ID übergibt. Wenn für die Formatvorlagen-ID keine Übereinstimmung gefunden wird, versucht der Code, die Formatvorlagen-ID zu finden, indem er die GetStyleIdFromStyleName-Beispielmethode aufruft und ihr den Formatvorlagennamen übergibt.

Wenn die Formatvorlage nicht vorhanden ist, weil der Formatvorlagenteil nicht vorhanden war, oder der Formatvorlagenteil vorhanden ist, aber die Formatvorlage nicht vorhanden ist, ruft der Code die AddNewStyle-Beispielmethode auf, um die Formatvorlage hinzuzufügen.

    // Get the Styles part for this document.
    StyleDefinitionsPart part =
        doc.MainDocumentPart.StyleDefinitionsPart;

    // If the Styles part does not exist, add it and then add the style.
    if (part == null)
    {
        part = AddStylesPartToPackage(doc);
        AddNewStyle(part, styleid, stylename);
    }
    else
    {
        // If the style is not in the document, add it.
        if (IsStyleIdInDocument(doc, styleid) != true)
        {
            // No match on styleid, so let's try style name.
            string styleidFromName = GetStyleIdFromStyleName(doc, stylename);
            if (styleidFromName == null)
            {
                AddNewStyle(part, styleid, stylename);
            }
            else
                styleid = styleidFromName;
        }
    }

Innerhalb der IsStyleInDocument-Beispielmethode beginnt die Arbeit mit dem Abrufen des Styles-Elements durch die Styles-Eigenschaft vom StyleDefinitionsPart des Hauptdokumentteils und durch das anschließende Bestimmen, ob alle Formatvorlagen als untergeordnete Elemente dieses Elements vorhanden sind. Alle Formatvorlagenelemente werden als untergeordnete Elemente des Formatvorlagenelements gespeichert.

Wenn Formatvorlagen vorhanden sind, sucht der Code nach einer Übereinstimmung für die styleid. Die styleid ist ein Attribut der Formatvorlage, das an vielen Stellen im Dokument verwendet wird, um auf die Formatvorlage zu verweisen, und kann als primärer Bezeichner betrachtet werden. In der Regel verwenden Sie die Formatvorlagen-ID, um eine Formatvorlage im Code zu identifizieren. Die FirstOrDefault-Methode ist standardmäßig null, wenn keine Übereinstimmung gefunden wird, sodass der Code überprüft, ob eine Formatvorlage übereinstimmt, wie im folgenden Auszug gezeigt.

    // Return true if the style id is in the document, false otherwise.
    public static bool IsStyleIdInDocument(WordprocessingDocument doc, 
        string styleid)
    {
        // Get access to the Styles element for this document.
        Styles s = doc.MainDocumentPart.StyleDefinitionsPart.Styles;

        // Check that there are styles and how many.
        int n = s.Elements<Style>().Count();
        if (n==0)
            return false;

        // Look for a match on styleid.
        Style style = s.Elements<Style>()
            .Where(st => (st.StyleId == styleid) && (st.Type == StyleValues.Paragraph))
            .FirstOrDefault();
        if (style == null)
                return false;
        
        return true;
    }

Wenn die Formatvorlage nicht basierend auf der styleid gefunden werden kann, versucht der Code stattdessen, eine Übereinstimmung basierend auf dem Formatvorlagennamen zu finden. Die GetStyleIdFromStyleName-Beispielmethode führt diese Arbeit aus und sucht nach einer Übereinstimmung für den Formatvorlagennamen und gibt die Styleid für das übereinstimmende Element zurück, falls gefunden, oder NULL, wenn nicht.

Hinzufügen der Formatvorlage zum Formatvorlagenteil

Die AddNewStyle-Beispielmethode enthält drei Parameter. Der erste Parameter enthält einen Verweis auf den Formatvorlagenteil. Der zweite Parameter enthält die Formatvorlagen-ID der Formatvorlage und der dritte Parameter enthält den Formatvorlagennamen. Der AddNewStyle-Code erstellt die benannte Formatvorlagendefinition innerhalb des angegebenen Teils.

Um die Formatvorlage zu erstellen, instanziiert der Code die Style-Klasse und legt bestimmte Eigenschaften wie z. B. den Typ der Formatvorlage (Absatz) und die Formatvorlagen-ID fest. Wie bereits erwähnt, wird die Formatvorlagen-ID vom Dokument zum Verweisen auf die Formatvorlage verwendet und kann als primärer Bezeichner betrachtet werden. In der Regel verwenden Sie die Formatvorlagen-ID, um eine Formatvorlage im Code zu identifizieren. Eine Formatvorlage kann auch einen separaten Anzeigenamen haben, der auf der Benutzeroberfläche angezeigt wird. Häufig wird der Formatvorlagenname daher unter Beachtung von Groß-/Kleinschreibung und mit Leerzeichen (z. B. "Überschrift 1") angezeigt, während die Formatvorlagen-ID kurz gehalten (z. B. "überschrift1") und nur für die interne Verwendung vorgesehen ist. Im folgenden Beispielcode werden die Werte für die Formatvorlagen-ID und den Formatvorlagennamen aus den Parametern der Formatvorlagen-ID und des Formatvorlagennamens übernommen.

Der nächste Schritt besteht im Angeben einiger zusätzlicher Eigenschaften wie der Formatvorlage, auf der die neue Formatvorlage basiert, und der automatisch auf den nächsten Absatz anzuwendenden Formatvorlage. Im Code werden beide als Formatvorlage "Normal" angegeben. Beachten Sie, dass der hier anzugebende Wert die Formatvorlagen-ID für die Formatvorlage "Normal" ist. Der Code fügt diese Eigenschaften als untergeordnete Elemente des Formatvorlagenelements an.

Nachdem der Code die Formatvorlage instanziiert und die grundlegenden Eigenschaften eingerichtet hat, arbeiten Sie nun an der Formatvorlagenformatierung. Die Formatvorlagenformatierung wird an den Elementen der Absatzeigenschaften (pPr) und der Laufeigenschaften (rPr) vorgenommen. Um die Schriftart und Farbe für die Läufe in einem Absatz festzulegen, müssen Sie die Laufeigenschaften verwenden.

Zum Erstellen des rPr-Elements mit den entsprechenden untergeordneten Elementen erstellt der Code eine Instanz der StyleRunProperties-Klasse und fügt dann Instanzen der entsprechenden Eigenschaftenklassen hinzu. Für dieses Codebeispiel gibt die Formatvorlage die Schriftart Lucida Console, einen Schriftgrad von 12 in Fett- und Kursivdruck mit der Farbe Accent2 aus dem Dokumentdesignteil an. Der Schriftgrad ist in halben Punkten angegeben, sodass der Wert 24 den 12 Punkten entspricht.

Wenn die Formatvorlagendefinition abgeschlossen ist, fügt der Code die Formatvorlage an das Formatvorlagenelement im Formatvorlagenteil an, wie im folgenden Codebeispiel dargestellt ist.

    // Create a new style with the specified styleid and stylename and add it to the specified
    // style definitions part.
    private static void AddNewStyle(StyleDefinitionsPart styleDefinitionsPart, 
        string styleid, string stylename)
    {
        // Get access to the root element of the styles part.
        Styles styles = styleDefinitionsPart.Styles;

        // Create a new paragraph style and specify some of the properties.
        Style style = new Style() { Type = StyleValues.Paragraph, 
            StyleId = styleid, 
            CustomStyle = true };
        StyleName styleName1 = new StyleName() { Val = stylename };
        BasedOn basedOn1 = new BasedOn() { Val = "Normal" };
        NextParagraphStyle nextParagraphStyle1 = new NextParagraphStyle() { Val = "Normal" };
        style.Append(styleName1);
        style.Append(basedOn1);
        style.Append(nextParagraphStyle1);

        // Create the StyleRunProperties object and specify some of the run properties.
        StyleRunProperties styleRunProperties1 = new StyleRunProperties();
        Bold bold1 = new Bold();
        Color color1 = new Color() { ThemeColor = ThemeColorValues.Accent2 };
        RunFonts font1 = new RunFonts() { Ascii = "Lucida Console" };
        Italic italic1 = new Italic();
        // Specify a 12 point size.
        FontSize fontSize1 = new FontSize() { Val = "24" };
        styleRunProperties1.Append(bold1);
        styleRunProperties1.Append(color1);
        styleRunProperties1.Append(font1);
        styleRunProperties1.Append(fontSize1);
        styleRunProperties1.Append(italic1);
        
        // Add the run properties to the style.
        style.Append(styleRunProperties1);
        
        // Add the style to the styles part.
        styles.Append(style);
    }

Anwenden der Formatvorlage auf den Absatz

Nun hat der Beispielcode den Absatz gefunden, bei Bedarf das erforderliche Absatzeigenschaftenelement hinzugefügt, auf den Formatvorlagenteil überprüft und bei Bedarf hinzugefügt, und es wurde auf die Formatvorlage überprüft und bei Bedarf hinzugefügt. Legen Sie nun die Absatzformatvorlage fest. Um diese Aufgabe auszuführen, erstellt der Code eine instance der ParagraphStyleId-Klasse mit der styleid und platziert dann einen Verweis auf diese instance in der ParagraphStyleId-Eigenschaft des Absatzeigenschaftenobjekts. Dadurch wird der entsprechende Wert dem pStyle-Element erstellt und zugewiesen, das die für den Absatz zu verwendende Formatvorlage angibt.

    // Set the style of the paragraph.
    pPr.ParagraphStyleId = new ParagraphStyleId(){Val = styleid};

Beispielcode

Sie können die ApplyStyleToParagraph-Beispielmethode verwenden, um mit dem Open XML-SDK auf einen Absatz in einem Dokument aus einem Textverarbeitungsprogramm eine Formatvorlage anzuwenden. Der folgende Code veranschaulicht, wie Sie einen Verweis auf ein Dokument aus einem Textverarbeitungsprogramm öffnen und abrufen, wie Sie einen Verweis auf den ersten Absatz abrufen und dann die ApplyStyleToParagraph-Methode aufrufen.

Zum Aufrufen der Methode übergeben Sie den Verweis auf das Dokument als ersten Parameter, die Formatvorlagen-ID der anzuwendenden Formatvorlage als zweiten Parameter, den Namen der Formatvorlage als dritten Parameter und den Verweis auf den Absatz, auf den die Formatvorlage angewendet werden soll, als vierten Parameter. Der folgende Code wendet beispielsweise die Formatvorlage "Overdue Amount" auf den ersten Absatz der Beispielsdatei mit dem Namen "ApplyStyleToParagraph.docx" an.

    string filename = @"C:\Users\Public\Documents\ApplyStyleToParagraph.docx";

    using (WordprocessingDocument doc =
        WordprocessingDocument.Open(filename, true))
    {
        // Get the first paragraph.
        Paragraph p =
          doc.MainDocumentPart.Document.Body.Descendants<Paragraph>()
          .ElementAtOrDefault(1);

        // Check for a null reference. 
        if (p == null)
        {
            throw new ArgumentOutOfRangeException("p", 
                "Paragraph was not found.");
        }

        ApplyStyleToParagraph(doc, "OverdueAmount", "Overdue Amount", p);
    }

Nachstehend ist der vollständige Beispielcode in C# und Visual Basic aufgeführt.


using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Linq;


// Apply a style to a paragraph.
static void ApplyStyleToParagraph(WordprocessingDocument doc, string styleid, string stylename, Paragraph p)
{
    if (doc is null)
    {
        throw new ArgumentNullException(nameof(doc));
    }
    // If the paragraph has no ParagraphProperties object, create one.
    if (p.Elements<ParagraphProperties>().Count() == 0)
    {
        p.PrependChild<ParagraphProperties>(new ParagraphProperties());
    }

    // Get the paragraph properties element of the paragraph.
    ParagraphProperties pPr = p.Elements<ParagraphProperties>().First();

    // Get the Styles part for this document.
    StyleDefinitionsPart? part = doc.MainDocumentPart?.StyleDefinitionsPart;

    // If the Styles part does not exist, add it and then add the style.
    if (part is null)
    {
        part = AddStylesPartToPackage(doc);
        AddNewStyle(part, styleid, stylename);
    }
    else
    {
        // If the style is not in the document, add it.
        if (IsStyleIdInDocument(doc, styleid) != true)
        {
            // No match on styleid, so let's try style name.
            string? styleidFromName = GetStyleIdFromStyleName(doc, stylename);

            if (styleidFromName is null)
            {
                AddNewStyle(part, styleid, stylename);
            }
            else
                styleid = styleidFromName;
        }
    }

    // Set the style of the paragraph.
    pPr.ParagraphStyleId = new ParagraphStyleId() { Val = styleid };
}

// Return true if the style id is in the document, false otherwise.
static bool IsStyleIdInDocument(WordprocessingDocument doc, string styleid)
{
    // Get access to the Styles element for this document.
    Styles? s = doc.MainDocumentPart?.StyleDefinitionsPart?.Styles;

    if (s is null)
    {
        return false;
    }

    // Check that there are styles and how many.
    int n = s.Elements<Style>().Count();

    if (n == 0)
    {
        return false;
    }

    // Look for a match on styleid.
    Style? style = s.Elements<Style>()
        .Where(st => (st.StyleId is not null && st.StyleId == styleid) && (st.Type is not null && st.Type == StyleValues.Paragraph))
        .FirstOrDefault();
    if (style is null)
    {
        return false;
    }

    return true;
}

// Return styleid that matches the styleName, or null when there's no match.
static string? GetStyleIdFromStyleName(WordprocessingDocument doc, string styleName)
{
    StyleDefinitionsPart? stylePart = doc.MainDocumentPart?.StyleDefinitionsPart;
    string? styleId = stylePart?.Styles?.Descendants<StyleName>()
        .Where(s =>
        {
            OpenXmlElement? p = s.Parent;
            EnumValue<StyleValues>? styleValue = p is null ? null : ((Style)p).Type;

            return s.Val is not null && s.Val.Value is not null && s.Val.Value.Equals(styleName) &&
            (styleValue is not null && styleValue == StyleValues.Paragraph);
        })
        .Select(n =>
        {

            OpenXmlElement? p = n.Parent;
            return p is null ? null : ((Style)p).StyleId;
        }).FirstOrDefault();

    return styleId;
}

// Create a new style with the specified styleid and stylename and add it to the specified
// style definitions part.
static void AddNewStyle(StyleDefinitionsPart styleDefinitionsPart, string styleid, string stylename)
{
    // Get access to the root element of the styles part.
    styleDefinitionsPart.Styles ??= new Styles();
    Styles styles = styleDefinitionsPart.Styles;

    // Create a new paragraph style and specify some of the properties.
    Style style = new Style()
    {
        Type = StyleValues.Paragraph,
        StyleId = styleid,
        CustomStyle = true
    };
    StyleName styleName1 = new StyleName() { Val = stylename };
    BasedOn basedOn1 = new BasedOn() { Val = "Normal" };
    NextParagraphStyle nextParagraphStyle1 = new NextParagraphStyle() { Val = "Normal" };
    style.Append(styleName1);
    style.Append(basedOn1);
    style.Append(nextParagraphStyle1);

    // Create the StyleRunProperties object and specify some of the run properties.
    StyleRunProperties styleRunProperties1 = new StyleRunProperties();
    Bold bold1 = new Bold();
    Color color1 = new Color() { ThemeColor = ThemeColorValues.Accent2 };
    RunFonts font1 = new RunFonts() { Ascii = "Lucida Console" };
    Italic italic1 = new Italic();
    // Specify a 12 point size.
    FontSize fontSize1 = new FontSize() { Val = "24" };
    styleRunProperties1.Append(bold1);
    styleRunProperties1.Append(color1);
    styleRunProperties1.Append(font1);
    styleRunProperties1.Append(fontSize1);
    styleRunProperties1.Append(italic1);

    // Add the run properties to the style.
    style.Append(styleRunProperties1);

    // Add the style to the styles part.
    styles.Append(style);
}

// Add a StylesDefinitionsPart to the document.  Returns a reference to it.
static StyleDefinitionsPart AddStylesPartToPackage(WordprocessingDocument doc)
{
    MainDocumentPart mainDocumentPart = doc.MainDocumentPart ?? doc.AddMainDocumentPart();
    StyleDefinitionsPart part = mainDocumentPart.AddNewPart<StyleDefinitionsPart>();
    Styles root = new Styles();
    root.Save(part);

    return part;
}