Erstellen von Open XML-WordprocessingML-Tabellen mit vertikal verbundenen Zellen

Zusammenfassung:   Informationen zum Erstellen von Tabellen mit vertikal verbundenen Zellen in Open XML-WordprocessingML-Dokumenten.

Letzte Änderung: Freitag, 4. November 2011

Gilt für: Office 2010 | Open XML | Visual Studio Tools for Microsoft Office | Word 2007 | Word 2010

Inhalt dieses Artikels
Einführung
Grundlegendes zum Markup
Generieren von Tabellen mit verbundenen Zellen
Beispiel: Erstellen von Tabellen mit vertikal verbundenen Zellen
Abschluss
Weitere Ressourcen

Inhalt

  • Einführung

  • Grundlegendes zum Markup

  • Generieren von Tabellen mit verbundenen Zellen

  • Beispiel: Erstellen von Tabellen mit vertikal verbundenen Zellen

  • Abschluss

  • Weitere Ressourcen

Einführung

Durch vertikales Verbinden der Zellen einer Tabelle in Textverarbeitungsdokumenten wird die Lesbarkeit verbessert. So kann in einer Tabelle, die Rechnungen für mehrere Anbieter enthält, durch Verbinden der Zellen eines Anbieters leichter nachvollzogen werden, welche Rechnungen zu diesem Anbieter gehören. Beim Generieren von Dokumenten können Sie Tabellen generieren, die vertikal verbundene Zellen enthalten. In diesem Artikel wird das Markup beschrieben, und ein Beispiel für das Generieren einer Tabelle mit vertikal verbundenen Zellen wird bereitgestellt.

Die folgende Abbildung zeigt eine Tabelle ohne vertikal verbundene Zellen.

Abbildung 1: Tabelle ohne vertikal verbundene Zellen

Tabelle ohne vertikal verbundene Zellen

Die folgende Abbildung zeigt die gleiche Tabelle mit vertikal verbundenen Zellen.

Abbildung 2: Tabelle mit vertikal verbundenen Zellen

Tabelle mit vertikal verbundenen Zellen

Grundlegendes zum Markup

Das Markup zum vertikalen Verbinden von Zellen ist nicht komplex. Zunächst soll jedoch das Tabellenmarkup in WordprocessingML betrachtet werden.

  • Tabellen (w:tbl) enthalten Zeilen (w:tr). Zeilen enthalten Zellen (w:tc), die wiederum Inhalte auf Blockebene enthalten, z. B. Absätze (w:p).

  • Ein gängiges Muster in WordprocessingML sind bestimmte Elemente, die ein untergeordnetes property-Element enthalten. Gemäß der Benennungskonvention folgt auf den Namen des übergeordneten Elements das Element "Pr". Beispielsweise enthalten Tabellen ein untergeordnetes Table Property-Element (w:tblPr). Zeilen enthalten ein untergeordnetes Table Row Property-Element (w:trPr).

Die vertikale Verbindung wird mit dem Table Cell Property-Element gesteuert (w:tcPr). Dieses Element kann ein untergeordnetes Vertically Merged Cell-Element enthalten (w:vMerge). Wenn w:vMerge ein w:val-Attribut mit dem Wert "restart" enthält, stellt die enthaltende Zelle die oberste Zelle einer Spalte vertikal verbundener Zellen dar. Wenn w:vMerge ein w:val-Attribut mit dem Wert "continue" enthält, wird die enthaltende Zelle mit der vorangehenden Zelle verbunden, die ein w:val-Attribut mit dem Wert "restart" enthält.

Einfach gesagt: Der Wert "restart" wird in die oberste Zelle eingefügt, und der Wert "continue" in die darauf folgenden Zellen. Im folgenden Beispiel wird das Markup für eine Tabelle mit vertikal verbundenen Zellen veranschaulicht. Die Darstellung der Tabelle wurde zum besseren Verständnis vereinfacht. Es handelt sich jedoch um gültiges WordprocessingML.

<w:tbl>
  <w:tblPr>
    <w:tblStyle w:val="TableGrid" />
    <w:tblW w:w="0"
            w:type="auto" />
    <w:tblLook w:val="04A0"
               w:firstRow="1"
               w:lastRow="0"
               w:firstColumn="1"
               w:lastColumn="0"
               w:noHBand="0"
               w:noVBand="1" />
  </w:tblPr>
  <w:tr>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>Vendor Number</w:t>
        </w:r>
      </w:p>
    </w:tc>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>Invoice Number</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:tr>
  <w:tr>
    <w:tc>
      <w:tcPr>
        <w:vMerge w:val="restart" />
      </w:tcPr>
      <w:p>
        <w:r>
          <w:t>1</w:t>
        </w:r>
      </w:p>
    </w:tc>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>37</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:tr>
  <w:tr>
    <w:tc>
      <w:tcPr>
        <w:vMerge w:val="continue" />
      </w:tcPr>
      <w:p />
    </w:tc>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>38</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:tr>
  <w:tr>
    <w:tc>
      <w:tcPr>
        <w:vMerge w:val="continue" />
      </w:tcPr>
      <w:p />
    </w:tc>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>39</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:tr>
  <w:tr>
    <w:tc>
      <w:tcPr>
        <w:vMerge w:val="restart" />
      </w:tcPr>
      <w:p>
        <w:r>
          <w:t>2</w:t>
        </w:r>
      </w:p>
    </w:tc>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>52</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:tr>
  <w:tr>
    <w:tc>
      <w:tcPr>
        <w:vMerge w:val="continue" />
      </w:tcPr>
      <w:p />
    </w:tc>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>53</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:tr>
</w:tbl>

Das w:val-Attribut des w:vMerge -Elements weist standardmäßig den Wert "continue" auf, sodass von Word 2010 folgendes Markup generiert wird:

  <w:tr>
    <w:tc>
      <w:tcPr>
        <w:vMerge w:val="restart" />
      </w:tcPr>
      <w:p>
        <w:r>
          <w:t>2</w:t>
        </w:r>
      </w:p>
    </w:tc>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>52</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:tr>
  <w:tr>
    <w:tc>
      <w:tcPr>
        <w:vMerge />
      </w:tcPr>
      <w:p />
    </w:tc>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>53</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:tr>

Generieren von Tabellen mit verbundenen Zellen

Durch die Überprüfung des Markup wird das Generieren von Tabellen mit vertikal verbundenen Zellen vereinfacht. In aller Regel arbeiten Sie mit Daten in einer hierarchischen Struktur ähnlich der folgenden:

<Root>
  <Vendor VendorNumber='1'>
    <Invoice InvoiceNumber='37' />
    <Invoice InvoiceNumber='38' />
    <Invoice InvoiceNumber='39' />
  </Vendor>
  <Vendor VendorNumber='2'>
    <Invoice InvoiceNumber='52' />
    <Invoice InvoiceNumber='53' />
  </Vendor>
</Root>

Diese Daten sollen wie unten angegeben umgewandelt werden:

<Root>
  <Invoice Vendor="1" Invoice="37" First="true" />
  <Invoice Vendor="1" Invoice="38" First="false" />
  <Invoice Vendor="1" Invoice="39" First="false" />
  <Invoice Vendor="2" Invoice="52" First="true" />
  <Invoice Vendor="2" Invoice="53" First="false" />
</Root>

Nachfolgend wird eine LINQ-Abfrage und -Projektion veranschaulicht, mit der XML der ersten Form in XML der zweiten Form umgewandelt wird:

XElement data = XElement.Parse(
    @"<Root>
        <Vendor VendorNumber='1'>
          <Invoice InvoiceNumber='37' />
          <Invoice InvoiceNumber='38' />
          <Invoice InvoiceNumber='39' />
        </Vendor>
        <Vendor VendorNumber='2'>
          <Invoice InvoiceNumber='52' />
          <Invoice InvoiceNumber='53' />
        </Vendor>
      </Root>");

// First, transform the XML into a more usable form.
XElement newData = new XElement("Root",
    data.Elements("Vendor")
        .Elements("Invoice")
        .Select(i => new XElement("Invoice",
            new XAttribute("Vendor", i.Parent.Attribute("VendorNumber").Value),
            new XAttribute("Invoice", i.Attribute("InvoiceNumber").Value),
            new XAttribute("First", i.Parent.Elements().First() == i))));

In dieser Abfrage und Projektion bestimmt der Ausdruck i.Parent.Elements().First() == i, ob ein bestimmtes Element das erste Element in einer Folge untergeordneter Elemente darstellt.

Sie können nun Code erstellen, um eine Tabelle mit dem Vertical Merge-Element in den entsprechenden Zellen zu generieren. Am besten erstellen Sie diesen Code mit dem Document Reflector-Tool aus Willkommen beim Open XML SDK 2.0 für Microsoft Office. Im folgenden Beispiel sehen Sie, wo das Vertical Merge-Element vom Code mit dem entsprechenden Wert für das w:val-Attribut eingefügt wird.

// Open the document, and insert a table with vertically-merged cells as the first
// block-level content element in the document.
using (WordprocessingDocument doc =
    WordprocessingDocument.Open("Test.docx", true))
{
    Table table = new Table();
    TableProperties tableProperties = new TableProperties();
    TableStyle tableStyle = new TableStyle() { Val = "TableGrid" };
    TableWidth tableWidth = new TableWidth()
        { Width = "0", Type = TableWidthUnitValues.Auto };
    TableLook tableLook = new TableLook() { Val = "04A0", FirstRow = true,
        LastRow = false, FirstColumn = true, LastColumn = false,
        NoHorizontalBand = false, NoVerticalBand = true };
    tableProperties.Append(tableStyle);
    tableProperties.Append(tableWidth);
    tableProperties.Append(tableLook);
    table.Append(tableProperties);
    foreach (var invoice in newData.Elements("Invoice"))
    {
        TableRow tableRow = new TableRow();
        TableCell tableCell1 = new TableCell();
        TableCellProperties tableCellProperties = new TableCellProperties();
        VerticalMerge verticalMerge = new VerticalMerge()
        { Val = (bool)invoice.Attribute("First") ? MergedCellValues.Restart :MergedCellValues.Continue };
        tableCellProperties.Append(verticalMerge);
        Paragraph paragraph1 = new Paragraph();
        if ((bool)invoice.Attribute("First"))
        {
            Run run = new Run();
            Text text = new Text();
            text.Text = invoice.Attribute("Vendor").Value;
            run.Append(text);
            paragraph1.Append(run);
        }
        tableCell1.Append(tableCellProperties);
        tableCell1.Append(paragraph1);
        TableCell tableCell2 = new TableCell();
        Paragraph paragraph2 = new Paragraph();
        Run run2 = new Run();
        Text text2 = new Text();
        text2.Text = invoice.Attribute("Invoice").Value;
        run2.Append(text2);
        paragraph2.Append(run2);
        tableCell2.Append(paragraph2);
        tableRow.Append(tableCell1);
        tableRow.Append(tableCell2);
        table.Append(tableRow);
    }
    doc.MainDocumentPart.Document.Body.InsertAt(table, 0);
    // If there is not a TableGrid style, then create one.
    if (!doc.MainDocumentPart.StyleDefinitionsPart.Styles.Elements<Style>()
            .Any(s => s.StyleId == "TableGrid"))
        doc.MainDocumentPart.StyleDefinitionsPart.Styles.Append(
            GenerateStyle());
}

Beispiel: Erstellen von Tabellen mit vertikal verbundenen Zellen

Im folgenden Beispiel wird das Dokument Test.docx geöffnet, und eine Tabelle mit vertikal verbundenen Zellen wird am Anfang des Dokuments eingefügt. Der folgende Code wurde überwiegend mit dem Open XML SDK 2.0-Produktivitätstool generiert und anschließend anhand der vorliegenden Anforderungen bearbeitet. Weitere Informationen zum Open XML SDK 2.0-Produktivitätstool erhalten Sie im Video unter Announcing the Release of the December 2009 CTP for the Open XML SDK.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

class Program
{
    static void Main(string[] args)
    {
        XElement data = XElement.Parse(
            @"<Root>
                <Vendor VendorNumber='1'>
                  <Invoice InvoiceNumber='37' />
                  <Invoice InvoiceNumber='38' />
                  <Invoice InvoiceNumber='39' />
                </Vendor>
                <Vendor VendorNumber='2'>
                  <Invoice InvoiceNumber='52' />
                  <Invoice InvoiceNumber='53' />
                </Vendor>
              </Root>");

        // First, transform the XML into a more usable form.
        XElement newData = new XElement("Root",
            data.Elements("Vendor")
                .Elements("Invoice")
                .Select(i => new XElement("Invoice",
                    new XAttribute("Vendor", i.Parent.Attribute("VendorNumber").Value),
                    new XAttribute("Invoice", i.Attribute("InvoiceNumber").Value),
                    new XAttribute("First", i.Parent.Elements().First() == i))));

        // Open the document, and insert a table with vertically-merged cells as the first
        // block-level content element in the document.
        using (WordprocessingDocument doc =
            WordprocessingDocument.Open("Test.docx", true))
        {
            Table table = new Table();
            TableProperties tableProperties = new TableProperties();
            TableStyle tableStyle = new TableStyle() { Val = "TableGrid" };
            TableWidth tableWidth = new TableWidth()
                { Width = "0", Type = TableWidthUnitValues.Auto };
            TableLook tableLook = new TableLook() { Val = "04A0", FirstRow = true,
                LastRow = false, FirstColumn = true, LastColumn = false,
                NoHorizontalBand = false, NoVerticalBand = true };
            tableProperties.Append(tableStyle);
            tableProperties.Append(tableWidth);
            tableProperties.Append(tableLook);
            table.Append(tableProperties);
            foreach (var invoice in newData.Elements("Invoice"))
            {
                TableRow tableRow = new TableRow();
                TableCell tableCell1 = new TableCell();
                TableCellProperties tableCellProperties = new TableCellProperties();
                VerticalMerge verticalMerge = new VerticalMerge()
                { Val = (bool)invoice.Attribute("First") ? MergedCellValues.Restart :
                    MergedCellValues.Continue };
                tableCellProperties.Append(verticalMerge);
                Paragraph paragraph1 = new Paragraph();
                if ((bool)invoice.Attribute("First"))
                {
                    Run run = new Run();
                    Text text = new Text();
                    text.Text = invoice.Attribute("Vendor").Value;
                    run.Append(text);
                    paragraph1.Append(run);
                }
                tableCell1.Append(tableCellProperties);
                tableCell1.Append(paragraph1);
                TableCell tableCell2 = new TableCell();
                Paragraph paragraph2 = new Paragraph();
                Run run2 = new Run();
                Text text2 = new Text();
                text2.Text = invoice.Attribute("Invoice").Value;
                run2.Append(text2);
                paragraph2.Append(run2);
                tableCell2.Append(paragraph2);
                tableRow.Append(tableCell1);
                tableRow.Append(tableCell2);
                table.Append(tableRow);
            }
            doc.MainDocumentPart.Document.Body.InsertAt(table, 0);
            // If there is not a TableGrid style, then create one.
            if (!doc.MainDocumentPart.StyleDefinitionsPart.Styles.Elements<Style>()
                    .Any(s => s.StyleId == "TableGrid"))
                doc.MainDocumentPart.StyleDefinitionsPart.Styles.Append(
                    GenerateStyle());
        }
    }

    // Creates a Style instance and adds its children.
    public static Style GenerateStyle()
    {
        Style style1 = new Style() { Type = StyleValues.Table, StyleId = "TableGrid" };
        StyleName styleName1 = new StyleName() { Val = "Table Grid" };
        BasedOn basedOn1 = new BasedOn() { Val = "TableNormal" };
        UIPriority uIPriority1 = new UIPriority() { Val = 59 };
        Rsid rsid1 = new Rsid() { Val = "005F1CC5" };

        StyleParagraphProperties styleParagraphProperties1 = new StyleParagraphProperties();
        SpacingBetweenLines spacingBetweenLines1 = new SpacingBetweenLines() { After = "0",
            Line = "240", LineRule = LineSpacingRuleValues.Auto };

        styleParagraphProperties1.Append(spacingBetweenLines1);

        StyleTableProperties styleTableProperties1 = new StyleTableProperties();
        TableIndentation tableIndentation1 = new TableIndentation() { Width = 0,
            Type = TableWidthUnitValues.Dxa };

        TableBorders tableBorders1 = new TableBorders();
        TopBorder topBorder1 = new TopBorder() { Val = BorderValues.Single, Color = "auto",
            Size = (UInt32Value)4U, Space = (UInt32Value)0U };
        LeftBorder leftBorder1 = new LeftBorder() { Val = BorderValues.Single, Color = "auto",
            Size = (UInt32Value)4U, Space = (UInt32Value)0U };
        BottomBorder bottomBorder1 = new BottomBorder() { Val = BorderValues.Single,
            Color = "auto", Size = (UInt32Value)4U, Space = (UInt32Value)0U };
        RightBorder rightBorder1 = new RightBorder() { Val = BorderValues.Single,
            Color = "auto", Size = (UInt32Value)4U, Space = (UInt32Value)0U };
        InsideHorizontalBorder insideHorizontalBorder1 = new InsideHorizontalBorder()
            { Val = BorderValues.Single, Color = "auto", Size = (UInt32Value)4U,
                Space = (UInt32Value)0U };
        InsideVerticalBorder insideVerticalBorder1 = new InsideVerticalBorder() {
            Val = BorderValues.Single, Color = "auto", Size = (UInt32Value)4U,
            Space = (UInt32Value)0U };

        tableBorders1.Append(topBorder1);
        tableBorders1.Append(leftBorder1);
        tableBorders1.Append(bottomBorder1);
        tableBorders1.Append(rightBorder1);
        tableBorders1.Append(insideHorizontalBorder1);
        tableBorders1.Append(insideVerticalBorder1);

        TableCellMarginDefault tableCellMarginDefault1 = new TableCellMarginDefault();
        TopMargin topMargin1 = new TopMargin() { Width = "0", Type = TableWidthUnitValues.Dxa };
        TableCellLeftMargin tableCellLeftMargin1 = new TableCellLeftMargin() { Width = 108,
            Type = TableWidthValues.Dxa };
        BottomMargin bottomMargin1 = new BottomMargin() { Width = "0",
            Type = TableWidthUnitValues.Dxa };
        TableCellRightMargin tableCellRightMargin1 = new TableCellRightMargin() { Width = 108,
            Type = TableWidthValues.Dxa };

        tableCellMarginDefault1.Append(topMargin1);
        tableCellMarginDefault1.Append(tableCellLeftMargin1);
        tableCellMarginDefault1.Append(bottomMargin1);
        tableCellMarginDefault1.Append(tableCellRightMargin1);

        styleTableProperties1.Append(tableIndentation1);
        styleTableProperties1.Append(tableBorders1);
        styleTableProperties1.Append(tableCellMarginDefault1);

        style1.Append(styleName1);
        style1.Append(basedOn1);
        style1.Append(uIPriority1);
        style1.Append(rsid1);
        style1.Append(styleParagraphProperties1);
        style1.Append(styleTableProperties1);
        return style1;
    }
}

Abschluss

Das Generieren von Open XML -WordprocessingML-Dokumenten stellt eine gute Möglichkeit zur Automatisierung des Dokumentgenerierungsprozesses dar. Nachdem Sie ein Open XML-WordprocessingML-Dokument generiert haben, können Sie es mit Word-Automatisierungsdienste nach PDF oder XPS konvertieren, drucken oder per E-Mail versenden. Eine wichtige Funktion zur Verbesserung der Lesbarkeit von Tabellen in den generierten Dokumenten stellt die Verwendung von vertikal verbundenen Zellen dar.

Weitere Ressourcen

Im Open XML Developer Center auf MSDN finden Sie Artikel, Anleitungsvideos und Links zu Blogbeiträgen. Die folgenden Links enthalten wichtige Informationen für die ersten Schritte mit :

-
Download: Open XML SDK 2.0

-
Artikel: Creating Documents by Using the Open XML Format SDK 2.0 (Part 1 of 3)

-
Artikel: Creating Documents by Using the Open XML Format SDK 2.0 (Part 2 of 3)

-
Artikel: Creating Documents by Using the Open XML Format SDK 2.0 (Part 3 of 3)

-
Blogbeitrag: Comparison of Html/CSS Tables to WordprocessingML Tables