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

C# 如何更改新XML文档中属性的值?,c#,.net,xml,xmldocument,C#,.net,Xml,Xmldocument,我有一个数据库,其中有大量的XML文件正在等待更新。更新将擦除数据库中的所有文件。除了属性值之外,每个新文件都与以前的文件相同 但是我想将具有会话的每个属性类型保留为值。此属性多次出现在每个文件中。但是,它暂时不起作用:属性根本不更新) 如何根据另一个XML文件更改新XML文件中特定属性的值 这就是我到目前为止所做的 因此,我决定在擦除之前为每个文件使用以下代码找到这些属性的路径: List<XmlList> dBPathTypeSession = new List<XmlLi

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

但是我想将具有会话的每个属性
类型
保留为值。此属性多次出现在每个文件中。但是,它暂时不起作用:属性根本不更新)

如何根据另一个XML文件更改新XML文件中特定属性的值

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

因此,我决定在擦除之前为每个文件使用以下代码找到这些属性的路径:

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
每个文件中每个路径的信息包含在以下内容中:

//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(
.NETFramework 3.5
),我必须使用
XMLDocument
使其与代码中的所有其他内容相匹配

下面是一个例子,说明了更新前的
XML
是什么样子(简短版本)

下面是一个示例,说明我正在寻找的
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>

1.
0
//系统停留时段
//会话返回会话
//系统停留系统
//会议停留会议
红色
蓝色
如果我们将其与布尔代数进行比较,我们得到:

对于x=会话&y=系统

更新前=更新后->我们想要什么

x=x->x

x=y->x

y=x->x

y=y->y


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

问题是,您正在搜索具有名为
type
且值为
session
的属性的节点,如果当前值为
system
,则替换该值。这是行不通的,因为值不能同时为两者

您必须想要:

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

更新

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

Update2如果您不想将整个旧的
XmlDocument
立即存储在内存中(尽管我不明白为什么不),可以使用
类型
属性构建元素查找表,按路径索引,然后稍后使用:

    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);
        }
    }
常量字符串AttributeName=“type”; var lookup=oldDoc.DocumentElement.genderantsandself().OfType().Where(el=>el.HasAttribute(AttributeName)).ToLookup(el=>el.Path(),el=>el.AttributeName[AttributeName].Value); //后来 WalkMatchingElements(新的XmlElement[]{newDoc.DocumentElement},查找,(el,oldValue)=> { if(oldValue!=null&&oldValue==“会话”) el.SetAttribute(AttributeName,“会话”); }); 私有静态void WalkMatchingElements(IEnumerable元素、ILookup路径查找、操作) { var elementsByPath=elements.GroupBy(el=>el.Path()); foreach(elementsByPath中的变量elementsGroup) { foreach(elementsGroup.Zip中的var对(路径查找[elementsGroup.Key],(el,value)=>newkeyvaluepair(el,value))) 动作(pair.Key、pair.Value); foreach(elementsGroup中的var元素) WalkMatchingElements(element.ChildNodes.OfType()、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);
    }
}
公共静态类XmlNodeExtensions
{
公共静态字符串路径(此XmlElement元素)
{
if(元素==null)
抛出新ArgumentNullException();
返回元素.anteStorsandself().OfType().Reverse().Aggregate(新的StringBuilder(),(sb,el)=>sb.Append(“/”).Append(el.Name)).ToString();
}
公共静态IEnumerable AncestorsAndSelf(此XmlNode)
{
for(;node!=null;node=node.ParentNode)
收益回报节点;
}
公共静态IEnumerable子代和自身(此XmlNode根)
{
if(root==null)
屈服断裂;
产量回归根;
foreach(root.ChildNodes.Cast()中的var child)
foreach(child.genderantsandself()中的var subChild)
收益子代;
}
}
公共静态类EnumerableExtensions
{
//从.Net 4.0向后移植
公共静态IEnumerable Zip(此IEnumerable第一,IEnumerable第二,Func resultSelector)
{
如果(first==null)抛出新的ArgumentNullException(“first”);
如果(second==null)抛出新的ArgumentNullException(“second”);
如果(resultSelector==null)抛出新的ArgumentNullException(“resultSelector”);
返回zip运算符(第一个、第二个、结果选择器);
}
静态IEnumerable ZipIterator(IEnumerable first,IEnumerable second,Func resultSelector)
{
使用(IEnumerator e1=first.GetEnumerator())
使用(IEnumerator e2=second.GetEnumerator())
而(e1.MoveNext()&&e2.MoveNext())
产生返回结果选择器(e1.Current,e2.Current);
}
}

(我忘记了
Zip
不在.NET3.5中。)

问题中的代码的问题是
XmlNodeList
:它创建一个链接到
XML
文件的对象列表。因此,当文件被擦除时,
XmlNodeList
没有任何意义。因此,将这个XmlNode列表中的
string
更改为这些XPath就可以了

XmlNodeList nodes = root.SelectNodes("//node()[@type='session']");
List<string> xPathList = new List<string>();
foreach (XmlNode node in nodes)
{
    xPathList.Add(getXPath(node));
}

dBPathTypeSession.Add(new XmlList("b_session_type", i, xPathList));//table,row,paths
XmlList
类将需要
    foreach (XmlNode node in root.SelectNodes("//node()[@type='system']"))
        node.Attributes["type"].Value = "session";
    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");
                }
            });
    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);
    }
}
XmlNodeList nodes = root.SelectNodes("//node()[@type='session']");
List<string> xPathList = new List<string>();
foreach (XmlNode node in nodes)
{
    xPathList.Add(getXPath(node));
}

dBPathTypeSession.Add(new XmlList("b_session_type", i, xPathList));//table,row,paths
static public string getXPath(XmlNode _xmlNode)
{
    Stack<string> xpath = new Stack<string>();

    while (_xmlNode != null)
    {
        if (_xmlNode as XmlElement != null)
            xpath.Push(_xmlNode.Name);

        _xmlNode = _xmlNode.ParentNode as XmlElement;
    }
    return string.Join("/", xpath.ToArray());
}
foreach (string path in file.Paths)
{
    XmlNode node = doc.SelectSingleNode(path);
    if (node.Attributes["type"].Value == "system" && node.Attributes["type"].Value != null)
    {
        node.Attributes["type"].Value = "session";
    }
}
//push to DB