从XElement转换后无效的OpenXml

问题描述 投票:0回答:1

我正在使用this code从XElement转换为OpenXmlElement

    internal static OpenXmlElement ToOpenXml(this XElement xel)
    {
        using (var sw = new StreamWriter(new MemoryStream()))
        {
            sw.Write(xel.ToString());
            sw.Flush();
            sw.BaseStream.Seek(0, SeekOrigin.Begin);

            var re = OpenXmlReader.Create(sw.BaseStream);
            re.Read();

            var oxe = re.LoadCurrentElement();
            re.Close();
            return oxe;
        }
    }

在转换之前,我有一个XElement

    <w:ind w:firstLine="0" w:left="0" w:right="0"/>    

转换后看起来像这样

    <w:ind w:firstLine="0" w:end="0" w:start="0"/>

此元素然后使用以下命令通过OpenXml验证失败

    var v = new OpenXmlValidator();
    var errs = v.Validate(doc);

报告错误:

    Description="The 'http://schemas.openxmlformats.org/wordprocessingml/2006/main:start' attribute is not declared."
    Description="The 'http://schemas.openxmlformats.org/wordprocessingml/2006/main:end' attribute is not declared."

我是否需要做其他事情以将这些属性添加到架构中,还是需要找到一种从XElement转换为OpenXml的新方法?

我正在使用nuget包DocumentFormat.OpenXml版本2.9.1(最新)。

编辑:查看the OpenXml standard,似乎应该同时识别左/开始和右/结束,这表明OpenXmlValidator不太正确。大概我可以忽略那些验证错误了吗?

很多东西

c# linq-to-xml openxml
1个回答
1
投票

简短的答案是,您确实可以忽略那些特定的验证错误。在这种情况下,OpenXmlValidator不是最新的。

[此外,我将为您的ToOpenXml方法提供更优雅的实现(请注意,在C#8.0中添加了using声明)。

internal static OpenXmlElement ToOpenXmlElement(this XElement element)
{
    // Write XElement to MemoryStream.
    using var stream = new MemoryStream();
    element.Save(stream);
    stream.Seek(0, SeekOrigin.Begin);

    // Read OpenXmlElement from MemoryStream.
    using OpenXmlReader reader = OpenXmlReader.Create(stream);
    reader.Read();
    return reader.LoadCurrentElement();
}

如果您不使用C#8.0或使用声明,这是使用using语句的相应代码。

internal static OpenXmlElement ToOpenXmlElement(this XElement element)
{
    using (var stream = new MemoryStream())
    {
        // Write XElement to MemoryStream.
        element.Save(stream);
        stream.Seek(0, SeekOrigin.Begin);

        // Read OpenXmlElement from MemoryStream.
        using OpenXmlReader reader = OpenXmlReader.Create(stream);
        {
            reader.Read();
            return reader.LoadCurrentElement();
        }
    }
}

这里是相应的单元测试,它还演示了您必须通过w:document才能通过在过程中创建的w:ind实例更改Indentation元素的属性。

public class OpenXmlReaderTests
{
    private const string NamespaceUriW = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
    private static readonly string XmlnsW = $"xmlns:w=\"{NamespaceUriW}\"";

    private static readonly string IndText =
        $@"<w:ind {XmlnsW} w:firstLine=""10"" w:left=""20"" w:right=""30""/>";

    private static readonly string DocumentText =
        $@"<w:document {XmlnsW}><w:body><w:p><w:pPr>{IndText}</w:pPr></w:p></w:body></w:document>";

    [Fact]
    public void ConvertingDocumentChangesIndProperties()
    {
        XElement element = XElement.Parse(DocumentText);

        var document = (Document) element.ToOpenXmlElement();
        Indentation ind = document.Descendants<Indentation>().First();

        Assert.Null(ind.Left);
        Assert.Null(ind.Right);

        Assert.Equal("10", ind.FirstLine);
        Assert.Equal("20", ind.Start);
        Assert.Equal("30", ind.End);
    }

    [Fact]
    public void ConvertingIndDoesNotChangeIndProperties()
    {
        XElement element = XElement.Parse(IndText);

        var ind = (OpenXmlUnknownElement) element.ToOpenXmlElement();

        Assert.Equal("10", ind.GetAttribute("firstLine", NamespaceUriW).Value);
        Assert.Equal("20", ind.GetAttribute("left", NamespaceUriW).Value);
        Assert.Equal("30", ind.GetAttribute("right", NamespaceUriW).Value);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.