使用 OpenXML 在 Power Point 演示文稿中突出显示文本?

highlight text in a power point presentation using OpenXML?

我正在使用以下代码使用 openxml 在 power point 演示文稿 (.pptx) 中突出显示文本,但在 pptx 代码下方 - 它损坏文件并在打开 pptx 时要求修复,打开后突出显示单词但确实如此不保留格式。所以总共有 2 个问题:

1. File gets corrupted
2. Formatting is not preserved
But it highlights the text which i want (but it does not preserve formatting)

I have debuged my code line by line and problem is at below line, but i am not able to figure out what is the problem.

    highlightRun.InsertAt(runPro, 0);

我已经使用 openxml 生产力工具比较了 pptx 的两个文件,一个突出显示了一个不突出显示:我看到的区别如下:我没有使用两次 RunProperties 但它显示了 2 次 :

损坏的文件:

public Run GenerateRun()
        {
            Run run1 = new Run();

            RunProperties runProperties1 = new RunProperties(){ Language = "en-US", Dirty = false };
            runProperties1.SetAttribute(new OpenXmlAttribute("", "smtClean", "", "0"));

            SolidFill solidFill1 = new SolidFill();
            RgbColorModelHex rgbColorModelHex1 = new RgbColorModelHex(){ Val = "FFF000" };

            solidFill1.Append(rgbColorModelHex1);

            runProperties1.Append(solidFill1);

            RunProperties runProperties2 = new RunProperties(){ Language = "en-US", Dirty = false };
            runProperties2.SetAttribute(new OpenXmlAttribute("", "smtClean", "", "0"));

            SolidFill solidFill2 = new SolidFill();
            RgbColorModelHex rgbColorModelHex2 = new RgbColorModelHex(){ Val = "FFFF00" };

            solidFill2.Append(rgbColorModelHex2);

            runProperties2.Append(solidFill2);
            Text text1 = new Text();
            text1.Text = "gaits";

            run1.Append(runProperties1);
            run1.Append(runProperties2);
            run1.Append(text1);
            return run1;

}

<a:r xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
  <a:rPr lang="en-US" dirty="0" smtClean="0">
    <a:solidFill>
      <a:srgbClr val="FFF000" />
    </a:solidFill>
  </a:rPr>
  <a:rPr lang="en-US" dirty="0" smtClean="0">
    <a:solidFill>
      <a:srgbClr val="FFFF00" />
    </a:solidFill>
  </a:rPr>
  <a:t>gaits</a:t>
</a:r>

正确的文件:

    public class GeneratedClass
    {
        // Creates an Run instance and adds its children.
        public Run GenerateRun()
        {
            Run run1 = new Run();

            RunProperties runProperties1 = new RunProperties(){ Language = "en-US", Dirty = false };
            runProperties1.SetAttribute(new OpenXmlAttribute("", "smtClean", "", "0"));

            SolidFill solidFill1 = new SolidFill();
            RgbColorModelHex rgbColorModelHex1 = new RgbColorModelHex(){ Val = "FFFF00" };

            solidFill1.Append(rgbColorModelHex1);

            runProperties1.Append(solidFill1);
            Text text1 = new Text();
            text1.Text = "gaits";

            run1.Append(runProperties1);
            run1.Append(text1);
            return run1;
        }

<a:r xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
  <a:rPr lang="en-US" dirty="0" smtClean="0">
    <a:solidFill>
      <a:srgbClr val="FFFF00" />
    </a:solidFill>
  </a:rPr>
  <a:t>gaits</a:t>
</a:r>

我错过了什么?我的完整代码如下:

using OpenXmlDrawing = DocumentFormat.OpenXml.Drawing;
      private void HighLightTextPresentation(OpenXmlDrawing.Paragraph paragraph, string text)
            {           

                var found = paragraph
                    .Descendants<OpenXmlDrawing.Run>()
                    .Where(r => !string.IsNullOrEmpty(r.InnerText) && r.InnerText != "\s")
                    .Select(r =>
                    {
                        var runText = r.GetFirstChild<OpenXmlDrawing.Text>();
                        int index = runText.Text.IndexOf(text, StringComparison.OrdinalIgnoreCase);

                        // 'Run' is a reference to the text run we found,
                        // TextNode is a reference to the run's Text object,
                        // 'TokenIndex` is the index of the search string in run's text
                        return new { Run = r, TextNode = runText, TokenIndex = index };
                    })
                    .FirstOrDefault(o => o.TokenIndex >= 0);

                // Nothing found -- escape
                if (found == null)
                {
                    return;
                }

                // Create a node for highlighted text as a clone (to preserve formatting etc)
                var highlightRun = found.Run.CloneNode(true);

                // Add the highlight node after the found text run and set up the highlighting
                paragraph.InsertAfter(highlightRun, found.Run);
                highlightRun.GetFirstChild<OpenXmlDrawing.Text>().Text = text;

                DocumentFormat.OpenXml.Drawing.RunProperties runPro = new DocumentFormat.OpenXml.Drawing.RunProperties() { Language = "en-US", Dirty = false };
                runPro.SetAttribute(new OpenXmlAttribute("", "smtClean", "", "0"));

                //Apply color to searched text
                DocumentFormat.OpenXml.Drawing.SolidFill solidFill1 = new DocumentFormat.OpenXml.Drawing.SolidFill();
                DocumentFormat.OpenXml.Drawing.RgbColorModelHex rgbColorModelHex1 = new DocumentFormat.OpenXml.Drawing.RgbColorModelHex() { Val = "FFF000" };//Set Font-Color to Green (Hex "00B050").
                solidFill1.Append(rgbColorModelHex1);

                runPro.Append(solidFill1);
                highlightRun.InsertAt(runPro, 0);

                // Check if there's some text in the text run *after* the found text
                int remainderLength = found.TextNode.Text.Length - found.TokenIndex - text.Length;
                if (remainderLength > 0)
                {
                    // There is some text after the highlighted section --
                    // insert it in a separate text run after the highlighted text run
                    var remainderRun = found.Run.CloneNode(true);
                    paragraph.InsertAfter(remainderRun, highlightRun);
                    OpenXmlDrawing.Text textNode = remainderRun.GetFirstChild<OpenXmlDrawing.Text>();
                    textNode.Text = found.TextNode.Text.Substring(found.TokenIndex + text.Length);

                    // We need to set up this to preserve the spaces between text runs
                    //textNode.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Preserve);
                }

                // Check if there's some text *before* the found text
                if (found.TokenIndex > 0)
                {
                    // Something is left before the highlighted text,
                    // so make the original text run contain only that portion
                    found.TextNode.Text = found.TextNode.Text.Remove(found.TokenIndex);

                    // We need to set up this to preserve the spaces between text runs
                    //found.TextNode.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Preserve);
                }
                else
                {
                    // There's nothing before the highlighted text -- remove the unneeded text run
                    paragraph.RemoveChild(found.Run);
                }
            }

如评论中所述,"getting corrupted" 的原因是您通过在a:r 个元素 (Run) 而只允许一个。

因此在插入新元素之前,您应该首先检查 Run 中是否已经存在 RunProperties 元素。如果 RunProperties 元素已经存在,您应该重新使用它。

// Either reuse an existing RunProperties element,
// or create a new one if there's none
RunProperties runPro = highlightRun.Descendants<RunProperties>().FirstOrDefault() ??
    new RunProperties { Language = "en-US", Dirty = false };

// only add the element if it's really new, don't add existing one
if (runPro.Parent == null)
{
    highlightRun.InsertAt(runPro, 0);
}