从 XElement 转换后无效的 OpenXml
Invalid OpenXml after converting from XElement
我正在使用 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 ver 2.9.1(最新)。
编辑:查看 the OpenXml standard,似乎 left/start 和 right/end 都应该被识别,这表明 OpenXmlValidator 不太正确。大概我可以忽略那些验证错误吧?
非常感谢
简短的回答是您确实可以忽略那些特定的验证错误。 OpenXmlValidator
在这种情况下不是最新的。
我会另外提供更优雅的 ToOpenXml
方法实现(请注意 using 声明,这是在 C# 8.0 中添加的)。
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 声明,这里是带有 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);
}
}
我正在使用 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 ver 2.9.1(最新)。
编辑:查看 the OpenXml standard,似乎 left/start 和 right/end 都应该被识别,这表明 OpenXmlValidator 不太正确。大概我可以忽略那些验证错误吧?
非常感谢
简短的回答是您确实可以忽略那些特定的验证错误。 OpenXmlValidator
在这种情况下不是最新的。
我会另外提供更优雅的 ToOpenXml
方法实现(请注意 using 声明,这是在 C# 8.0 中添加的)。
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 声明,这里是带有 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);
}
}