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

时间:2018-11-27 16:57:51

标签: c# powerpoint openxml

我正在使用以下代码使用openxml突出显示Powerpoint演示文稿(.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的两个文件,其中一个未突出显示,一个突出显示:我看到的区别如下:我没有使用两次RunProperty,而是显示了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);
                }
            }

1 个答案:

答案 0 :(得分:2)

如评论中所述,“被破坏”的原因是,您可以通过在a:rPr元素中创建一个额外的RunProperties元素(a:r)来使XML结构无效( Run),而只允许一个。

因此,在插入新元素之前,应首先检查RunProperties中是否已经有Run元素。如果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);
}