- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我有两个基本格式相同的 XML 文件,但是 Master.XML 中的一些标签和属性不包含在 Child.XML 中。
我需要将 XML 文件合并到一个新的 XML 文件中,其中缺少标签和属性。
如果 Master.XML 和 Child.XML 中的值不同,则应使用 Child.XML 中的值。
我尝试对节点使用 Union 和 Concat,但它不起作用。
master.DescendantNodes().Union(child.DescendantNodes());
任何建议都会有所帮助。
Master.XML
<SysConfig IsRuntime="False" BarcodeEnabled="false" version="1.2.0.0">
<DbPath>C:\Agilent_i1000\ICPT_DB.sqlite</DbPath>
<CardDiagonsticsDelayTime>10</CardDiagonsticsDelayTime>
<ScreenSpecs NameID="CoreID" XrelativeID="X" YrelativeID="Y">
<ScreenSpec Name="MainCtrlPanel" Xrelative="0" Yrelative="0" ></ScreenSpec>
<ScreenSpec Name="1" Xrelative="75" Yrelative="0" NotToUse="1"></ScreenSpec>
<ScreenSpec Name="2" Xrelative="75" Yrelative="25" NotToUse="1"></ScreenSpec>
</ScreenSpecs>
</SysConfig>
Child.XML
<SysConfig IsRuntime="False" BarcodeEnabled="false" version="1.2.0.0">
<CardDiagonsticsDelayTime>20</CardDiagonsticsDelayTime>
<ScreenSpecs NameID="CoreID" XrelativeID="X" YrelativeID="Y">
<ScreenSpec Name="MainCtrlPanel" Xrelative="0" Yrelative="0" ></ScreenSpec>
<ScreenSpec Name="1" Xrelative="100" Yrelative="0" ></ScreenSpec>
<ScreenSpec Name="2" Xrelative="75" Yrelative="25"></ScreenSpec>
<ScreenSpec Name="3" Xrelative="175" Yrelative="25"></ScreenSpec>
</ScreenSpecs>
</SysConfig>
预期输出
<SysConfig IsRuntime="False" BarcodeEnabled="false" version="1.2.0.0">
<DbPath>C:\Agilent_i1000\ICPT_DB.sqlite</DbPath>
<CardDiagonsticsDelayTime>20</CardDiagonsticsDelayTime>
<ScreenSpecs NameID="CoreID" XrelativeID="X" YrelativeID="Y">
<ScreenSpec Name="MainCtrlPanel" Xrelative="0" Yrelative="0" ></ScreenSpec>
<ScreenSpec Name="1" Xrelative="100" Yrelative="0" NotToUse="1" ></ScreenSpec>
<ScreenSpec Name="2" Xrelative="75" Yrelative="25" NotToUse="1"></ScreenSpec>
<ScreenSpec Name="3" Xrelative="175" Yrelative="25">
</ScreenSpec>
</ScreenSpecs>
</SysConfig>
最佳答案
这是一组能够合并两个 XML 文档的实用程序类。整个东西非常通用,但您可能需要对其进行修改以满足其他特定需求。
这是处理您的案例的代码:
var result = new XmlXPathDocument();
result.Load("master.xml");
var child = new XmlXPathDocument();
child.Load("child.xml");
// here we tell the class that "Name" is a discriminant attribute.
// two nodes at the same level with the same discriminant attributes are considered the same, so will be merged
// if we don't do this, they will considered different and they will be added if the set of their attributes is different
child.AddDiscriminantAttribute("Name", string.Empty);
child.InjectXml(result);
result.Save("output.xml");
这些类派生自标准 XmlDocument 类层次结构。他们使用自动计算的 XPATH 表达式来逐个节点地合并文档。
public class XmlXPathDocument : XmlDocument
{
public const string XmlNamespaceUri = "http://www.w3.org/2000/xmlns/";
public const string XmlNamespacePrefix = "xmlns";
internal List<Tuple<string, string>> _discriminantAttributes = new List<Tuple<string, string>>();
public XmlXPathDocument() => Construct();
public XmlXPathDocument(XmlNameTable nameTable) : base(nameTable) => Construct();
public XmlXPathDocument(XmlImplementation implementation) : base(implementation) => Construct();
protected virtual void Construct() => XPathNamespaceManager = new XmlNamespaceManager(new NameTable());
public virtual XmlNamespaceManager XPathNamespaceManager { get; private set; }
public override XmlElement CreateElement(string prefix, string localName, string namespaceURI) => new XmlXPathElement(prefix, localName, namespaceURI, this);
public override XmlCDataSection CreateCDataSection(string data) => new XmlXPathCDataSection(data, this);
public override XmlText CreateTextNode(string text) => new XmlXPathText(text, this);
public virtual void AddDiscriminantAttribute(string name, string namespaceURI)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
_discriminantAttributes.Add(new Tuple<string, string>(name, namespaceURI));
}
public virtual bool IsDiscriminant(XmlAttribute attribute)
{
if (attribute == null)
throw new ArgumentNullException(nameof(attribute));
foreach (var pair in _discriminantAttributes)
{
string ns = Nullify(attribute.NamespaceURI);
string dns = Nullify(pair.Item2);
if (ns == dns && pair.Item1 == attribute.LocalName)
return true;
}
return false;
}
private static string Nullify(string text)
{
if (text == null)
return null;
text = text.Trim();
if (text.Length == 0)
return null;
return text;
}
internal string GetPrefix(string namespaceURI)
{
if (string.IsNullOrEmpty(namespaceURI))
return null;
string prefix = XPathNamespaceManager.LookupPrefix(namespaceURI);
if (!string.IsNullOrEmpty(prefix))
{
XPathNamespaceManager.AddNamespace(prefix, namespaceURI);
return prefix;
}
string newPrefix;
int index = 0;
do
{
newPrefix = "ns" + index;
if (XPathNamespaceManager.LookupNamespace(newPrefix) == null)
break;
index++;
}
while (true);
XPathNamespaceManager.AddNamespace(newPrefix, namespaceURI);
return newPrefix;
}
private static bool IsNamespaceAttribute(XmlAttribute attribute)
{
if (attribute == null)
return false;
return attribute.NamespaceURI == XmlNamespaceUri && attribute.Prefix == XmlNamespacePrefix;
}
private static IEnumerable<XmlAttribute> GetAttributes(IXmlXPathNode node)
{
var xe = node as XmlElement;
if (xe == null)
yield break;
foreach (XmlAttribute att in xe.Attributes)
{
yield return att;
}
}
private static XmlAttribute GetAttribute(IXmlXPathNode node, string name) => node is XmlElement xe ? xe.Attributes[name] : null;
private static XmlAttribute GetAttribute(IXmlXPathNode node, string localName, string ns) => node is XmlElement xe ? xe.Attributes[localName, ns] : null;
public virtual bool InjectXml(XmlDocument target)
{
if (target == null)
throw new ArgumentNullException(nameof(target));
if (DocumentElement == null)
return false;
bool changed = false;
foreach (XmlNode node in SelectNodes("//node()"))
{
var xelement = node as IXmlXPathNode;
if (xelement == null)
continue;
if (string.IsNullOrEmpty(xelement.XPathExpression))
continue;
XmlNode other = target.SelectSingleNode(xelement.XPathExpression, XPathNamespaceManager);
if (other != null)
{
if (other is XmlElement otherElement)
{
foreach (XmlAttribute att in GetAttributes(xelement))
{
if (IsNamespaceAttribute(att))
continue;
if (otherElement.Attributes[att.LocalName, att.NamespaceURI]?.Value != att.Value)
{
otherElement.SetAttribute(att.LocalName, att.NamespaceURI, att.Value);
changed = true;
}
}
continue;
}
}
if (node is XmlXPathElement element)
{
XmlElement parent = EnsureTargetParent(xelement, target, out changed);
XmlElement targetElement = target.CreateElement(element.LocalName, element.NamespaceURI);
changed = true;
if (parent == null)
{
target.AppendChild(targetElement);
}
else
{
parent.AppendChild(targetElement);
}
foreach (XmlAttribute att in GetAttributes(xelement))
{
if (IsNamespaceAttribute(att))
continue;
targetElement.SetAttribute(att.LocalName, att.NamespaceURI, att.Value);
}
continue;
}
if (node is XmlXPathCDataSection cdata)
{
XmlElement parent = EnsureTargetParent(xelement, target, out changed);
var targetCData = target.CreateCDataSection(cdata.Value);
changed = true;
if (parent == null)
{
target.AppendChild(targetCData);
AppendNextTexts(node, targetCData, target);
}
else
{
if (parent.ChildNodes.Count == 1 && parent.ChildNodes[0] is XmlCharacterData)
{
parent.RemoveChild(parent.ChildNodes[0]);
}
parent.AppendChild(targetCData);
AppendNextTexts(node, targetCData, parent);
}
continue;
}
if (node is XmlXPathText text)
{
XmlElement parent = EnsureTargetParent(xelement, target, out changed);
var targetText = target.CreateTextNode(text.Value);
changed = true;
if (parent == null)
{
target.AppendChild(targetText);
AppendNextTexts(node, targetText, target);
}
else
{
if (parent.ChildNodes.Count == 1 && parent.ChildNodes[0] is XmlCharacterData)
{
parent.RemoveChild(parent.ChildNodes[0]);
}
parent.AppendChild(targetText);
AppendNextTexts(node, targetText, parent);
}
continue;
}
}
return changed;
}
private static void AppendNextTexts(XmlNode textNode, XmlNode targetTextNode, XmlNode parent)
{
do
{
if (textNode.NextSibling is XmlText text)
{
var newText = targetTextNode.OwnerDocument.CreateTextNode(text.Value);
parent.AppendChild(newText);
}
else
{
var cdata = textNode.NextSibling as XmlCDataSection;
if (cdata == null)
break;
var newCData = targetTextNode.OwnerDocument.CreateCDataSection(cdata.Value);
parent.AppendChild(newCData);
}
textNode = textNode.NextSibling;
}
while (true);
}
private static XmlElement EnsureTargetParent(IXmlXPathNode element, XmlDocument target, out bool changed)
{
changed = false;
if (element.ParentNode is XmlXPathElement parent)
{
if (string.IsNullOrEmpty(parent.XPathExpression))
return null;
if (target.SelectSingleNode(parent.XPathExpression, element.OwnerDocument.XPathNamespaceManager) is XmlElement targetElement)
return targetElement;
var parentElement = EnsureTargetParent(parent, target, out changed);
targetElement = target.CreateElement(parent.LocalName, parent.NamespaceURI);
parentElement.AppendChild(targetElement);
changed = true;
return targetElement;
}
return target.DocumentElement;
}
}
public class XmlXPathElement : XmlElement, IXmlXPathNode
{
private Lazy<string> _xPathExpression;
public XmlXPathElement(string prefix, string localName, string namespaceURI, XmlXPathDocument doc) : base(prefix, localName, namespaceURI, doc)
{
_xPathExpression = new Lazy<string>(() => GetXPathExpression());
}
public new XmlXPathDocument OwnerDocument => (XmlXPathDocument)base.OwnerDocument;
public virtual string XPathExpression => _xPathExpression.Value;
private static string GetAttEscapedValue(string value)
{
if (value.IndexOf('\'') >= 0)
return "=\"" + value.Replace("\"", """) + "\"";
return "='" + value + "'";
}
private string GetDiscriminantAttributeXPath()
{
foreach (var att in OwnerDocument._discriminantAttributes)
{
XmlAttribute disc;
if (string.IsNullOrEmpty(att.Item2))
{
disc = GetAttributeNode(att.Item1);
}
else
{
disc = GetAttributeNode(att.Item1, att.Item2);
}
if (disc != null)
{
string newPrefix = OwnerDocument.GetPrefix(NamespaceURI);
string name = Name + "[@" + disc.Name + GetAttEscapedValue(disc.Value) + "]";
if (newPrefix != null)
{
name = newPrefix + ":" + name;
}
return name;
}
}
return null;
}
private string GetAttributesXPath()
{
if (Attributes.Count == 0)
return null;
var sb = new StringBuilder();
foreach (XmlAttribute att in Attributes)
{
if (sb.Length > 0)
{
sb.Append(" and ");
}
sb.Append("@");
sb.Append(att.Name);
sb.Append(GetAttEscapedValue(att.Value));
OwnerDocument.GetPrefix(att.NamespaceURI);
}
var text = sb.ToString().Trim();
if (text.Length == 0)
return null;
return "[" + text + "]";
}
private string GetXPath(XmlNodeList parentNodes)
{
string discriminant = GetDiscriminantAttributeXPath();
if (discriminant != null)
return discriminant;
string name = Name;
string newPrefix = OwnerDocument.GetPrefix(NamespaceURI);
if (newPrefix != null)
{
name = newPrefix + ":" + LocalName;
}
if (parentNodes.Count == 1)
return name;
var sameName = new List<XmlElement>();
foreach (XmlNode node in parentNodes)
{
if (node.NodeType != XmlNodeType.Element)
continue;
if (node.Name == Name)
{
sameName.Add((XmlElement)node);
}
}
if (sameName.Count == 1)
return name;
string byIndex = null;
var sameAtts = new List<XmlElement>();
for (int i = 0; i < sameName.Count; i++)
{
if (sameName[i] == this)
{
byIndex = name + "[" + (i + 1) + "]";
continue;
}
bool same = true;
foreach (XmlAttribute att in Attributes)
{
XmlAttribute sameAtt = sameName[i].Attributes[att.LocalName, att.NamespaceURI];
if (sameAtt == null || string.Compare(sameAtt.Value, att.Value, StringComparison.OrdinalIgnoreCase) != 0)
{
same = false;
break;
}
}
if (same)
{
sameAtts.Add(sameName[i]);
}
}
if (sameAtts.Count == 0)
return name + GetAttributesXPath();
return byIndex;
}
private string GetXPathExpression()
{
if (ParentNode == null)
{
string name = Name;
string newPrefix = OwnerDocument.GetPrefix(NamespaceURI);
if (newPrefix != null)
{
name = newPrefix + ":" + name;
}
return name;
}
string expr = GetXPath(ParentNode.ChildNodes);
if (ParentNode is XmlXPathElement parent)
{
expr = parent.XPathExpression + "/" + expr;
}
if (ParentNode.NodeType == XmlNodeType.Document)
{
expr = "/" + expr;
}
return expr;
}
}
public class XmlXPathText : XmlText, IXmlXPathNode
{
private Lazy<string> _xPathExpression;
public XmlXPathText(string data, XmlXPathDocument doc) : base(data, doc)
{
_xPathExpression = new Lazy<string>(() => GetTextXPathExpression(this));
}
public new XmlXPathDocument OwnerDocument => (XmlXPathDocument)base.OwnerDocument;
public virtual string XPathExpression => _xPathExpression.Value;
internal static string GetTextXPathExpression(XmlNode node)
{
if (node.ParentNode is IXmlXPathNode element)
return element.XPathExpression + "/text()";
return null;
}
}
public class XmlXPathCDataSection : XmlCDataSection, IXmlXPathNode
{
private Lazy<string> _xPathExpression;
public XmlXPathCDataSection(string data, XmlXPathDocument doc) : base(data, doc)
{
_xPathExpression = new Lazy<string>(() => XmlXPathText.GetTextXPathExpression(this));
}
public new XmlXPathDocument OwnerDocument => (XmlXPathDocument)base.OwnerDocument;
public virtual string XPathExpression => _xPathExpression.Value;
}
public interface IXmlXPathNode
{
string XPathExpression { get; }
XmlNode ParentNode { get; }
XmlXPathDocument OwnerDocument { get; }
}
关于c# - 合并两个 XML 文件并添加缺少的标签和属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49483631/
我创建了一个用户可以添加测试的字段。这一切运行顺利我只希望当用户点击(添加另一个测试)然后上一个(添加另一个测试)删除并且这个显示在新字段中。 所有运行良好的唯一问题是点击(添加另一个字段)之前添加另
String[] option = {"Adlawan", "Angeles", "Arreza", "Benenoso", "Bermas", "Brebant
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
我正在努力将 jQuery 滚动功能添加到 nav-tab (Bootstrap 3)。我希望用户能够选择他们想要的选项卡,并在选项卡内容中有一个可以平滑滚动到 anchor 的链接。这是我的代码,可
我正在尝试在用户登录后再添加 2 个 ui 选项卡。首先,我尝试做一个之后。 $('#slideshow').tabs('remove', '4'); $("#slideshow ul li:last
我有一个包含选择元素的表单,我想通过选择添加和删除其中一些元素。这是html代码(这里也有jsfiddle http://jsfiddle.net/txhajy2w/):
正在写这个: view.backgroundColor = UIColor.white.withAlphaComponent(0.9) 等同于: view.backgroundColor = UICo
好的,如果其中有任何信息,我想将这些列添加到一起。所以说我有 账户 1 2 3 . 有 4 个帐户空间,但只有 3 个帐户。我如何创建 java 脚本来添加它。 最佳答案 Live Example H
我想知道是否有一种有效的预制算法来确定一组数字的和/差是否可以等于不同的数字。示例: 5、8、10、2,使用 + 或 - 等于 9。5 - 8 = -3 + 10 = 7 + 2 = 9 如果有一个预
我似乎有一个卡住的 git repo。它卡在所有基本的添加、提交命令上,git push 返回所有内容为最新的。 从其他帖子我已经完成了 git gc 和 git fsck/ 我认为基本的调试步骤是
我的 Oracle SQL 查询如下- Q1- select hca.account_number, hca.attribute3, SUM(rcl.extended_amou
我正在阅读 http://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingG
我正在尝试添加一个“加载更多”按钮并限制下面的结果,这样投资组合页面中就不会同时加载 1000 个内容,如下所示:http://typesetdesign.com/portfolio/ 我对 PHP
我遇到这个问题,我添加了 8 个文本框,它工作正常,但是当我添加更多文本框(如 16 个文本框)时,它不会添加最后一个文本框。有人遇到过这个问题吗?提前致谢。 Live Link: JAVASCRIP
add/remove clone first row default not delete 添加/删除克隆第一行默认不删除&并获取正确的SrNo(例如:添加3行并在看到问题后删除SrNo.2)
我编码this ,但删除按钮不起作用。我在控制台中没有任何错误.. var counter = 0; var dataList = document.getElementById('materi
我有一个类似数组的对象: [1:数组[10]、2:数组[2]、3:数组[2]、4:数组[2]、5:数组[3]、6:数组[1]] 我正在尝试删除前两个元素,执行一些操作,然后将它们再次插入到同一位置。
使用的 Delphi 版本:2007 你好, 我有一个 Tecord 数组 TInfo = Record Name : String; Price : Integer; end; var Info
我使用了基本的 gridster 代码,然后我声明了通过按钮添加和删除小部件的函数它工作正常但是当我将调整大小功能添加到上面的代码中时,它都不起作用(我的意思是调整大小,添加和删除小部件) 我的js代
title 323 323 323 title 323 323 323 title 323 323 323 JS $(document).keydown(function(e){
我是一名优秀的程序员,十分优秀!