【问题标题】:highlight text in a power point presentation using OpenXML?使用 OpenXML 在 power point 演示文稿中突出显示文本?
【发布时间】:2018-12-01 00:03:45
【问题描述】:

我使用下面的代码使用 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);
                }
            }

【问题讨论】:

  • 我的标准评论:从 Microsoft 网站下载 OpenXml 生产力工具。创建一个没有突出显示的 PPTX(使用 PowerPoint)。保存。然后复制文件,添加突出显示(在 PowerPoint 中)并保存该文件。打开工具。使用比较/差异功能查看两个文件之间的更改。该工具还将帮助您修复损坏的文件(并非总是如此,但经常如此)。
  • 在您的代码和您添加到帖子中的文档 xml 中,在我看来,您总是在创建一个新的 RunProperties 实例并将其插入到 Run 中,而不检查是否存在已经是其中一个现有的RunProperties 元素。并且 IIRC 每个 Run 只允许 1 个 RunProperties。在尝试添加新的之前,您是否尝试过检查现有的以替换或更新?
  • @bassfader:你什么意思?您可以为此发布一些示例代码吗?或者您的意思是这样说: if (!highlightRun.Contains(runProperties1)) highlightRun.InsertAt(runProperties1, 0);

标签: c# powerpoint openxml


【解决方案1】:

如 cmets 中所述,“损坏”的原因是您通过在 a:r 元素 (Run) 中创建额外的 a:rPr 元素 (RunProperties) 使 XML 结构无效,而仅一个是允许的。

所以在插入新元素之前,你应该先检查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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多