如何在 XML 树中加载和添加元素
How to load and add elements in an XML tree
过去几天我一直在阅读此处的 Stack Overflow、博客和 MSDN 文章。我显然缺乏对名称空间、Linq 和 XML 工作原理的一些基本了解,因此需要帮助。如果我有更多的头发要拔,它现在就在我手里了:-)
使用 C# 和 Linq XML,我打开以下 opf.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<package version="2.0" xmlns="http://www.idpf.org/2007/opf" unique-identifier="">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
</metadata>
<manifest></manifest>
<spine toc="ncx"></spine>
<guide></guide>
</package>
我用下面的代码打开这个文件:
File.Copy(_opfFile, opfFile, true);
XDocument opfDoc = XDocument.Load(opfFile);
不幸的是,在这里我完全迷路了。我需要做的是在每个主要节点下生成元素。对于 metadata
节点,我需要创建具有名称空间和非名称空间的元素。对于文件的其余部分,我只需要添加不使用命名空间的常规节点。
下面是我想要实现的输出示例。我相信如果你能帮助我处理 metdata
和 manifest
节点,我就能弄清楚如何更新其余节点。
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns:ibooks="http://www.idpf.org/2007/opf" unique-identifier="BookId" version="3.0" prefix="ibooks: http://www.idpf.org/2007/opf" xmlns="http://www.idpf.org/2007/opf">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:title>Untitled</dc:title>
<meta refines="#contributor" property="role" scheme="marc:relators">bkp</meta>
</metadata>
<manifest>
<item id="toc" href="toc.xhtml" media-type="application/xhtml+xml" properties="nav"/>
</manifest>
<spine toc="ncx"></spine>
<guide></guide>
</package>
能否请您提供一些基本的 C#/Linq 代码给:
- 查找并添加
metadata
项需要 "dc" 的命名空间 (ns),如上例所示。
- 添加一个
metadata
项目,该项目不使用上述示例中的命名空间。
- 添加新的
manifest
项,如上例所示。
我会分享我写的代码,但它到处都是,我有很多注释代码。我可以告诉你的是,我经常以空异常错误告终。
提前致谢。
在使用多个命名空间进行逆向工程 XML 时,我发现以下调试实用程序很有用:
public static class XObjectExtensions
{
public static IEnumerable<string> DumpXmlAttributeNames(this XObject obj)
{
if (obj is XAttribute)
return new[] { ((XAttribute)obj).Name.ToString() };
else if (obj is XElement)
{
return ((XElement)obj).Attributes().Select(a => a.Name.ToString());
}
return Enumerable.Empty<string>();
}
public static IEnumerable<string> DumpXmlElementNames(this XElement root)
{
if (root == null)
return Enumerable.Empty<string>();
return root.DescendantsAndSelf().Select(el => string.Format("{0} \"{1}\"; Attribute names: {2}",
new string(' ', el.AncestorsAndSelf().Count()), el.Name.ToString(), String.Join(", ", el.DumpXmlAttributeNames().Select(s => "\"" + s + "\""))));
}
public static IEnumerable<string> DumpXmlElementNames(this XDocument root)
{
if (root == null)
return Enumerable.Empty<string>();
return root.Root.DumpXmlElementNames();
}
}
使用它们,可以轻松查看所需元素和属性的正确命名空间 XML:
"{http://www.idpf.org/2007/opf}package"; Attribute names: "{http://www.w3.org/2000/xmlns/}ibooks", "unique-identifier", "version", "prefix", "xmlns"
"{http://www.idpf.org/2007/opf}metadata"; Attribute names: "{http://www.w3.org/2000/xmlns/}dc", "{http://www.w3.org/2000/xmlns/}opf"
"{http://purl.org/dc/elements/1.1/}title"; Attribute names:
"{http://www.idpf.org/2007/opf}meta"; Attribute names: "refines", "property", "scheme"
"{http://www.idpf.org/2007/opf}manifest"; Attribute names:
"{http://www.idpf.org/2007/opf}item"; Attribute names: "id", "href", "media-type", "properties"
"{http://www.idpf.org/2007/opf}spine"; Attribute names: "toc"
"{http://www.idpf.org/2007/opf}guide"; Attribute names:
因此您需要在 "http://purl.org/dc/elements/1.1/"
命名空间中添加 "title"
元素,在 "http://www.idpf.org/2007/opf"
命名空间中添加其他元素:
var dc = (XNamespace)"http://purl.org/dc/elements/1.1/";
var opf = (XNamespace)"http://www.idpf.org/2007/opf";
var meta = opfDoc.Root.Element(opf + "metadata");
meta.Add(new XElement(dc + "title", "Untitled"));
meta.Add(new XElement(opf + "meta",
new XAttribute("refines", "#contributor"),
new XAttribute("property", "role"),
new XAttribute("scheme", "marc:relators"), "bkp"));
var manifest = opfDoc.Root.Element(opf + "manifest");
manifest.Add(new XElement(opf + "item",
new XAttribute("id", "toc"),
new XAttribute("href", "toc.xhtml"),
new XAttribute("media-type", "application/xhtml+xml"),
new XAttribute("properties", "nav")));
过去几天我一直在阅读此处的 Stack Overflow、博客和 MSDN 文章。我显然缺乏对名称空间、Linq 和 XML 工作原理的一些基本了解,因此需要帮助。如果我有更多的头发要拔,它现在就在我手里了:-)
使用 C# 和 Linq XML,我打开以下 opf.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<package version="2.0" xmlns="http://www.idpf.org/2007/opf" unique-identifier="">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
</metadata>
<manifest></manifest>
<spine toc="ncx"></spine>
<guide></guide>
</package>
我用下面的代码打开这个文件:
File.Copy(_opfFile, opfFile, true);
XDocument opfDoc = XDocument.Load(opfFile);
不幸的是,在这里我完全迷路了。我需要做的是在每个主要节点下生成元素。对于 metadata
节点,我需要创建具有名称空间和非名称空间的元素。对于文件的其余部分,我只需要添加不使用命名空间的常规节点。
下面是我想要实现的输出示例。我相信如果你能帮助我处理 metdata
和 manifest
节点,我就能弄清楚如何更新其余节点。
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns:ibooks="http://www.idpf.org/2007/opf" unique-identifier="BookId" version="3.0" prefix="ibooks: http://www.idpf.org/2007/opf" xmlns="http://www.idpf.org/2007/opf">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:title>Untitled</dc:title>
<meta refines="#contributor" property="role" scheme="marc:relators">bkp</meta>
</metadata>
<manifest>
<item id="toc" href="toc.xhtml" media-type="application/xhtml+xml" properties="nav"/>
</manifest>
<spine toc="ncx"></spine>
<guide></guide>
</package>
能否请您提供一些基本的 C#/Linq 代码给:
- 查找并添加
metadata
项需要 "dc" 的命名空间 (ns),如上例所示。 - 添加一个
metadata
项目,该项目不使用上述示例中的命名空间。 - 添加新的
manifest
项,如上例所示。
我会分享我写的代码,但它到处都是,我有很多注释代码。我可以告诉你的是,我经常以空异常错误告终。
提前致谢。
在使用多个命名空间进行逆向工程 XML 时,我发现以下调试实用程序很有用:
public static class XObjectExtensions
{
public static IEnumerable<string> DumpXmlAttributeNames(this XObject obj)
{
if (obj is XAttribute)
return new[] { ((XAttribute)obj).Name.ToString() };
else if (obj is XElement)
{
return ((XElement)obj).Attributes().Select(a => a.Name.ToString());
}
return Enumerable.Empty<string>();
}
public static IEnumerable<string> DumpXmlElementNames(this XElement root)
{
if (root == null)
return Enumerable.Empty<string>();
return root.DescendantsAndSelf().Select(el => string.Format("{0} \"{1}\"; Attribute names: {2}",
new string(' ', el.AncestorsAndSelf().Count()), el.Name.ToString(), String.Join(", ", el.DumpXmlAttributeNames().Select(s => "\"" + s + "\""))));
}
public static IEnumerable<string> DumpXmlElementNames(this XDocument root)
{
if (root == null)
return Enumerable.Empty<string>();
return root.Root.DumpXmlElementNames();
}
}
使用它们,可以轻松查看所需元素和属性的正确命名空间 XML:
"{http://www.idpf.org/2007/opf}package"; Attribute names: "{http://www.w3.org/2000/xmlns/}ibooks", "unique-identifier", "version", "prefix", "xmlns" "{http://www.idpf.org/2007/opf}metadata"; Attribute names: "{http://www.w3.org/2000/xmlns/}dc", "{http://www.w3.org/2000/xmlns/}opf" "{http://purl.org/dc/elements/1.1/}title"; Attribute names: "{http://www.idpf.org/2007/opf}meta"; Attribute names: "refines", "property", "scheme" "{http://www.idpf.org/2007/opf}manifest"; Attribute names: "{http://www.idpf.org/2007/opf}item"; Attribute names: "id", "href", "media-type", "properties" "{http://www.idpf.org/2007/opf}spine"; Attribute names: "toc" "{http://www.idpf.org/2007/opf}guide"; Attribute names:
因此您需要在 "http://purl.org/dc/elements/1.1/"
命名空间中添加 "title"
元素,在 "http://www.idpf.org/2007/opf"
命名空间中添加其他元素:
var dc = (XNamespace)"http://purl.org/dc/elements/1.1/";
var opf = (XNamespace)"http://www.idpf.org/2007/opf";
var meta = opfDoc.Root.Element(opf + "metadata");
meta.Add(new XElement(dc + "title", "Untitled"));
meta.Add(new XElement(opf + "meta",
new XAttribute("refines", "#contributor"),
new XAttribute("property", "role"),
new XAttribute("scheme", "marc:relators"), "bkp"));
var manifest = opfDoc.Root.Element(opf + "manifest");
manifest.Add(new XElement(opf + "item",
new XAttribute("id", "toc"),
new XAttribute("href", "toc.xhtml"),
new XAttribute("media-type", "application/xhtml+xml"),
new XAttribute("properties", "nav")));