Ошибка использования Open XML для чтения файла .docx из потока памяти в WordprocessingDocument в строку и обратно - PullRequest
0 голосов
/ 25 февраля 2020

У меня есть существующая библиотека, которую я могу использовать, чтобы получить файл docx и вернуть его. Программное обеспечение. Net Ядро размещено в Linux Docker контейнере.

Хотя его область действия очень ограничена, и мне нужно выполнить некоторые действия, которые он не может выполнить. Поскольку они просты, я подумал, что буду использовать Open XML, и для доказательства своей концепции все, что мне нужно сделать, это прочитать docx как поток памяти, заменить некоторый текст, превратить его в поток памяти и вернуть его.

Однако возвращаемый документ не читается. Я закомментировал замену текста ниже, чтобы устранить это, и если я закомментирую вызов метода ниже, тогда docx можно будет прочитать, поэтому я уверен, что проблема в этом методе.

Предположительно я я делаю что-то здесь в корне неправильно, но после нескольких часов гуглил и играл с кодом, я не уверен, как это исправить; Есть идеи, что я не прав?

Спасибо за помощь

private MemoryStream SearchAndReplace(MemoryStream mem)
{
    mem.Position = 0;

    using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(mem, true))
    {
        string docText = null;

        StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream());
        docText = sr.ReadToEnd();

        //Regex regexText = new Regex("Hello world!");
        //docText = regexText.Replace(docText, "Hi Everyone!");


        MemoryStream newMem = new MemoryStream();
        newMem.Position = 0;
        StreamWriter sw = new StreamWriter(newMem);
        sw.Write(docText);

        return newMem;
    }
}

1 Ответ

0 голосов
/ 28 февраля 2020

Если ваше реальное требование заключается в поиске и замене текста в WordprocessingDocument, вы должны взглянуть на этот ответ .

Следующий модульный тест показывает, как вы можете сделать подходите к работе, если сценарий использования действительно требует, чтобы вы прочитали строку из детали, «помассировали» строку и записали измененную строку обратно в деталь. Это также показывает один из недостатков любого другого подхода, кроме описанного в ответе , уже упомянутом выше, например, демонстрируя, что строка "Hello world!" не будет найдена таким образом, если она разбита w:r элементов.

[Fact]
public void CanSearchAndReplaceStringInOpenXmlPartAlthoughThisIsNotTheWayToSearchAndReplaceText()
{
    // Arrange.
    using var docxStream = new MemoryStream();
    using (var wordDocument = WordprocessingDocument.Create(docxStream, WordprocessingDocumentType.Document))
    {
        MainDocumentPart part = wordDocument.AddMainDocumentPart();
        var p1 = new Paragraph(
            new Run(
                new Text("Hello world!")));

        var p2 = new Paragraph(
            new Run(
                new Text("Hello ") { Space = SpaceProcessingModeValues.Preserve }),
            new Run(
                new Text("world!")));

        part.Document = new Document(new Body(p1, p2));

        Assert.Equal("Hello world!", p1.InnerText);
        Assert.Equal("Hello world!", p2.InnerText);
    }

    // Act.
    SearchAndReplace(docxStream);

    // Assert.
    using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(docxStream, false))
    {
        MainDocumentPart part = wordDocument.MainDocumentPart;
        Paragraph p1 = part.Document.Descendants<Paragraph>().First();
        Paragraph p2 = part.Document.Descendants<Paragraph>().Last();

        Assert.Equal("Hi Everyone!", p1.InnerText);
        Assert.Equal("Hello world!", p2.InnerText);
    }
}

private static void SearchAndReplace(MemoryStream docxStream)
{
    using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(docxStream, true))
    {
        // If you wanted to read the part's contents as text, this is how you
        // would do it.
        string partText = ReadPartText(wordDocument.MainDocumentPart);

        // Note that this is not the way in which you should search and replace
        // text in Open XML documents. The text might be split across multiple
        // w:r elements, so you would not find the text in that case.
        var regex = new Regex("Hello world!");
        partText = regex.Replace(partText, "Hi Everyone!");

        // If you wanted to write changed text back to the part, this is how
        // you would do it.
        WritePartText(wordDocument.MainDocumentPart, partText);
    }

    docxStream.Seek(0, SeekOrigin.Begin);
}

private static string ReadPartText(OpenXmlPart part)
{
    using Stream partStream = part.GetStream(FileMode.OpenOrCreate, FileAccess.Read);
    using var sr = new StreamReader(partStream);
    return sr.ReadToEnd();
}

private static void WritePartText(OpenXmlPart part, string text)
{
    using Stream partStream = part.GetStream(FileMode.Create, FileAccess.Write);
    using var sw = new StreamWriter(partStream);
    sw.Write(text);
}
...