gpt4 book ai didi

c# - 如何更改新 XML 文档中属性的值?

转载 作者:太空宇宙 更新时间:2023-11-03 10:34:58 27 4
gpt4 key购买 nike

我有一个数据库,其中有大量等待更新的 XML 文件。更新将删除数据库中的所有文件。除了属性值之外,每个新文件都将与他之前的文件相同。

但我想保留每个属性 type 具有 session 作为值。该属性多次出现在每个文件中。但是,它暂时不起作用:属性根本不更新)。

How can I change the value of an specific attribute in an new XML file identical depending of another one?

这就是我到目前为止所做的......

所以我决定找到一种方法,在删除之前为每个文件使用此代码来获取这些属性的路径:

List<XmlList> dBPathTypeSession = new List<XmlList>();
/*reader*/
XmlDocument doc = new XmlDocument();
doc.LoadXml(sessionType.Parameters);

XmlNode root = doc.DocumentElement;

//I think my problem come from this line below
XmlNodeList nodes = root.SelectNodes("//node()[@type='session']");

dBPathTypeSession.Add(new XmlList("b_session_type", i, nodes));//table,row,paths

The code below this line is probably not needed to answer my question, this is just more detail.

然后在更新后更正属性值:

XmlDocument doc = new XmlDocument();
doc.LoadXml(sessionType.Parameters);

foreach (XmlNode node in file.Paths)//XmlList file = new XmlList();
{
if (node.Attributes["type"].Value == "system")
{
node.Attributes["type"].Value = "session";
}
}
//push to DB

每个文件中每个路径的信息都包含在这个:

//But I think this is pointless for my question
public class XmlList
{
public XmlList(string tablePath, int filePath, XmlNodeList paths)
{
this.TablePath = tablePath;
this.FilePath = filePath;
this.Paths = paths;
}
public string TablePath {get; private set;}
public int FilePath {get; private set;}
public XmlNodeList Paths {get;set;}
}

我使用的是 C# 3.0(.NET framework 3.5),我必须使用 XMLDocument 使其适合代码中的所有其他内容。

这是更新前 XML 的示例(简短版本)

<Session is_hidden="false">
<ID is_static="true">1</ID>
<SESSIONIDX is_static="true">0</SESSIONIDX>
<Timing>
<FirstPresentation display_name="FirstPresentation" type="system"/>
<Pause display_name="Pause" type="system" datatype="float"/>
<Feedback display_name="Feedback" type="session" datatype="float"/>
<Answer display_name="Answer" type="system" datatype="float"/>
</Timing>
<Balls>
<Indexed display_name="Indexed" type="session" datatype="pos_int"/>
<IndexingColor1 display_name="IndexingColor1" type="system" datatype="list">
<list>
<ListItem>RED</ListItem>
<ListItem>BLUE</ListItem>
</list>
</IndexingColor1>
</Balls>
</Session>

这是更新后 XML 的示例(简短版)

<Session is_hidden="false">
<ID is_static="true">1</ID>
<SESSIONIDX is_static="true">0</SESSIONIDX>
<Timing>
<FirstPresentation display_name="FirstPresentation" type="session"/>//system change for session
<Pause display_name="Pause" type="system" datatype="float"/>
<Feedback display_name="Feedback" type="system" datatype="float"/>//session change for system
<Answer display_name="Answer" type="system" datatype="float"/>//system stay system
</Timing>
<Balls>
<Indexed display_name="Indexed" type="session" datatype="pos_int"/>//session stay session
<IndexingColor1 display_name="IndexingColor1" type="system" datatype="list">
<list>
<ListItem>RED</ListItem>
<ListItem>BLUE</ListItem>
</list>
</IndexingColor1>
</Balls>
</Session>

下面是我正在寻找的 XML 示例:

<Session is_hidden="false">
<ID is_static="true">1</ID>
<SESSIONIDX is_static="true">0</SESSIONIDX>
<Timing>
<FirstPresentation display_name="FirstPresentation" type="session"/>//system stay session
<Pause display_name="Pause" type="system" datatype="float"/>
<Feedback display_name="Feedback" type="session" datatype="float"/>//session return session
<Answer display_name="Answer" type="system" datatype="float"/>//system stay system
</Timing>
<Balls>
<Indexed display_name="Indexed" type="session" datatype="pos_int"/>//session stay session
<IndexingColor1 display_name="IndexingColor1" type="system" datatype="list">
<list>
<ListItem>RED</ListItem>
<ListItem>BLUE</ListItem>
</list>
</IndexingColor1>
</Balls>
</Session>

如果我们将其与 bool 代数进行比较,我们有:

For x = session & y = system

before update = after update -> What we want

x = x -> x

x = y -> x

y = x -> x

y = y -> y

如果您需要更多信息,请在评论中提问,我会更新帖子。

最佳答案

问题是您正在搜索具有名为 type 且值为 session 的属性的节点——然后如果 current 替换该值值为 系统。那是行不通的,因为值(value)不能兼而有之。

你必须要:

    foreach (XmlNode node in root.SelectNodes("//node()[@type='session']"))
node.Attributes["type"].Value = "system";

    foreach (XmlNode node in root.SelectNodes("//node()[@type='system']"))
node.Attributes["type"].Value = "session";

更新

如果您有两个 XmlDocuments,它们具有相同的元素层次结构但每个元素的属性集不同,并且希望将一些属性信息从第一个传播到第二个,您需要遍历元素层次结构并在它们之间创建临时映射表。以下是这样做的,假设元素按名称对应,然后如果存在重复名称(例如在列表中)则按顺序:

    static void WalkMatchingElements(XmlElement root1, XmlElement root2, Action<XmlElement, XmlElement> action)
{
WalkMatchingElements(root1, root2, (element) => (element.Name), action);
}

static void WalkMatchingElements<TKey>(XmlElement root1, XmlElement root2, Func<XmlElement, TKey> getKey, Action<XmlElement, XmlElement> action)
{
if (EqualityComparer<TKey>.Default.Equals(getKey(root1), getKey(root2)))
action(root1, root2);
var children1GroupedByName = root1.ChildNodes.OfType<XmlElement>().GroupBy(getKey);
var children2LookupByName = root2.ChildNodes.OfType<XmlElement>().ToLookup(getKey);
foreach (var child1group in children1GroupedByName)
{
var child2group = children2LookupByName[child1group.Key];
foreach (var pair in child1group.Zip(child2group, (el1, el2) => new KeyValuePair<XmlElement, XmlElement>(el1, el2)))
WalkMatchingElements(pair.Key, pair.Value, getKey, action);
}
}

然后这样调用它:

        var oldDoc = new XmlDocument();
oldDoc.LoadXml(oldXml);

var newDoc = new XmlDocument();
newDoc.LoadXml(newXml);

WalkMatchingElements(oldDoc.DocumentElement, newDoc.DocumentElement, (elOld, elNew) =>
{
var attrOld = elOld.Attributes["type"];
if (attrOld != null && attrOld.Value == "session")
{
elNew.SetAttribute("type", "system");
}
});

Update2 如果您不想立即将整个旧的 XmlDocument 存入内存(尽管我不明白为什么不这样做),您可以构建一个查找表具有 type 属性的元素,由路径索引,稍后使用:

    const string AttributeName = "type";

var lookup = oldDoc.DocumentElement.DescendantsAndSelf().OfType<XmlElement>().Where(el => el.HasAttribute(AttributeName)).ToLookup(el => el.Path(), el => el.Attributes[AttributeName].Value);

// And then later

WalkMatchingElements(new XmlElement[] { newDoc.DocumentElement }, lookup, (el, oldValue) =>
{
if (oldValue != null && oldValue == "session")
el.SetAttribute(AttributeName, "session");
});


private static void WalkMatchingElements<TValue>(IEnumerable<XmlElement> elements, ILookup<string, TValue> pathLookup, Action<XmlElement, TValue> action)
{
var elementsByPath = elements.GroupBy(el => el.Path());
foreach (var elementsGroup in elementsByPath)
{
foreach (var pair in elementsGroup.Zip(pathLookup[elementsGroup.Key], (el, value) => new KeyValuePair<XmlElement, TValue>(el, value)))
action(pair.Key, pair.Value);
foreach (var element in elementsGroup)
WalkMatchingElements(element.ChildNodes.OfType<XmlElement>(), pathLookup, action);
}
}

您需要以下扩展方法:

public static class XmlNodeExtensions
{
public static string Path(this XmlElement element)
{
if (element == null)
throw new ArgumentNullException();
return element.AncestorsAndSelf().OfType<XmlElement>().Reverse().Aggregate(new StringBuilder(), (sb, el) => sb.Append("/").Append(el.Name)).ToString();
}

public static IEnumerable<XmlNode> AncestorsAndSelf(this XmlNode node)
{
for (; node != null; node = node.ParentNode)
yield return node;
}

public static IEnumerable<XmlNode> DescendantsAndSelf(this XmlNode root)
{
if (root == null)
yield break;
yield return root;
foreach (var child in root.ChildNodes.Cast<XmlNode>())
foreach (var subChild in child.DescendantsAndSelf())
yield return subChild;
}
}

public static class EnumerableExtensions
{
// Back ported from .Net 4.0
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
{
if (first == null) throw new ArgumentNullException("first");
if (second == null) throw new ArgumentNullException("second");
if (resultSelector == null) throw new ArgumentNullException("resultSelector");
return ZipIterator(first, second, resultSelector);
}

static IEnumerable<TResult> ZipIterator<TFirst, TSecond, TResult>(IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
{
using (IEnumerator<TFirst> e1 = first.GetEnumerator())
using (IEnumerator<TSecond> e2 = second.GetEnumerator())
while (e1.MoveNext() && e2.MoveNext())
yield return resultSelector(e1.Current, e2.Current);
}
}

(我忘记了 Zip 不在 .Net 3.5 中。)

关于c# - 如何更改新 XML 文档中属性的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28118175/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com