如何用我自己的XElement对象替换特定的XElement对象?

时间:2015-04-13 19:27:09

标签: c# xml linq xpath

我正在处理一个程序,该程序将图片插入到文档中指定位置的Microsoft Word文档中。例如,一个文本显示为" AUTOREPLACE 111"的页面,我会将其替换为以111开头的特定文件夹中的所有图像。

我可以使用Microsoft.Office.Interop.Word执行此操作,但此方法需要相对较长的时间来处理。添加了几百个图像,对于添加的每个图像,我必须添加裁剪值以及操纵图像对象中的其他几个变量。相对长的时间,我的意思是这需要至少一个小时来处理整个文档。

过去几天我一直在寻找更快的方法,并决定解压缩.docx文件,将图像添加到 media 文件夹,然后操纵必要的。用于将包含AUTOREPLACE文本的元素替换为图片元素的xml文档。

以下是包含AUTOREPLACE元素的xml:

<w:p w:rsidR="00411330" w:rsidRDefault="00411330" w:rsidP="005C6ED0">
    <w:pPr>
        <w:tabs>
            <w:tab w:val="left" w:pos="720"/>
            <w:tab w:val="left" w:pos="1260"/>
        </w:tabs>
        <w:rPr>
            <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>
        </w:rPr>
    </w:pPr>
    <w:r>
        <w:rPr>
            <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>
        </w:rPr>
        <w:br w:type="page"/>
    </w:r>
    <w:r>
        <w:rPr>
            <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>
        </w:rPr>
        <w:lastRenderedPageBreak/>
        <w:t>AUTOREPLACE 111</w:t>
    </w:r>
</w:p>

这是替换上面的xml

的w:p元素的xml
<w:p w:rsidR="0080275B" w:rsidRDefault="0080275B" w:rsidP="0080275B">
    <w:pPr>
        <w:jc w:val="center"/>
    </w:pPr>
    <w:r>
        <w:rPr>
            <w:noProof/>
        </w:rPr>
        <w:lastRenderedPageBreak/>
        <w:drawing>
            <wp:inline distT="0" distB="0" distL="0" distR="0">
                <wp:extent cx="6031373" cy="8255000"/>
                <wp:effectExtent l="0" t="0" r="7620" b="0"/>
                <wp:docPr id="1" name="Picture 1"/>
                <wp:cNvGraphicFramePr>
                    <a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/>
                </wp:cNvGraphicFramePr>
                <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
                    <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
                        <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
                            <pic:nvPicPr>
                                <pic:cNvPr id="0" name=""/>
                                <pic:cNvPicPr/>
                            </pic:nvPicPr>
                            <pic:blipFill>
                                <a:blip r:embed="rId17" r:link="rId18"/>
                                <a:srcRect l="7516" t="4798" r="4248" b="1768"/>
                                <a:stretch>
                                    <a:fillRect/>
                                </a:stretch>
                            </pic:blipFill>
                            <pic:spPr>
                                <a:xfrm>
                                    <a:off x="0" y="0"/>
                                    <a:ext cx="6031373" cy="8255000"/>
                                </a:xfrm>
                                <a:prstGeom prst="rect">
                                    <a:avLst/>
                                </a:prstGeom>
                            </pic:spPr>
                        </pic:pic>
                    </a:graphicData>
                </a:graphic>
            </wp:inline>
        </w:drawing>
    </w:r>
    <w:r w:rsidR="00411330">
        <w:br w:type="page"/>
    </w:r>
</w:p>

我现在尝试设置的方法将遍历加载的XDocument的节点,直到它到达需要替换的节点,并将其替换为我创建的XElement对象。

我能够创建正确的w:p XElement,但是我在用我创建的元素替换原始元素时遇到了麻烦。

以下是从解压缩的Word文档中加载的document.xml的前3行:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 wp14">
        <w:body>

替换后的 w:p 元素是 w:body

的子元素

这是我到目前为止的测试代码:

XElement replaceElement = new XElement("replace");
ImagePageCreation iPage;

XDocument xdoc = XDocument.Load(xmlPath);
bool ReplaceFound = false;
XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";

foreach (XElement xe in xdoc.Descendants(w + "p"))
{
    foreach (XElement xr in xe.Descendants(w + "r"))
    {
        foreach (XElement xt in xr.Descendants(w + "t"))
        {
            string innerText = xt.Value;
            if (innerText.Length > 10)
            {
                if (!ReplaceFound)
                {
                    if (innerText.Substring(0, 11) == "AUTOREPLACE")
                    {
                        //Console.WriteLine(innerText);
                        iPage = new ImagePageCreation("0080275B", "0080275B", "0080275B");
                        replaceElement = iPage.GetFullElement();
                        ReplaceFound = true;
                        break;
                    }
                }
            }
        }
        if (ReplaceFound)
        {
            break;
        }
    }
    if (ReplaceFound)
    {
        xe = replaceElement;
    }
}

我无法执行xe = replaceElement,因为xe是一个foreach迭代变量&#39;。

识别包含w:r元素的w:\ t元素的最佳方法是什么,该元素包含值为AUTOREPLACE 111的w:t元素并将其替换为我自己的w:p元素?

编辑:我知道我发布的代码示例只能在第一次替换时正常工作。我希望更换工作,然后我将纠正循环逻辑。

1 个答案:

答案 0 :(得分:0)

您可以使用XNode.ReplaceWith()方法将原始节点替换为替换,例如:

        var query = from xe in xdoc.Descendants(w + "p")
                    let replacement = xe
                        .Descendants(w + "r").Descendants(w + "t")
                        .Where(xt => xt.Value.StartsWith("AUTOREPLACE"))
                        .Select(xt => new ImagePageCreation("0080275B", "0080275B", "0080275B").GetFullElement())
                        .FirstOrDefault()
                    where replacement != null
                    select new { Original = xe, Replacement = replacement };
        foreach (var pair in query.ToList())
        {
            pair.Original.ReplaceWith(pair.Replacement);
        }

如果您有多个替换,可以将.FirstOrDefault()更改为.ToList()

        XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
        var query = from xe in xdoc.Descendants(w + "p")
                    let replacement = xe
                        .Descendants(w + "r").Descendants(w + "t")
                        .Where(xt => xt.Value.StartsWith("AUTOREPLACE"))
                        .Select(xt => new ImagePageCreation("0080275B", "0080275B", "0080275B").GetFullElement())
                        .ToList()
                    where replacement.Count > 0
                    select new { Original = xe, ReplacementList = replacement };
        foreach (var pair in query.ToList())
        {
            pair.Original.ReplaceWith(pair.ReplacementList);
        }