2016-01-14 39 views
4

我需要用指定用户的更新产品列表替换产品列表(UserCart)。我怎样才能在不调用每个属性的情况有没有办法一次替换整个XML节点?

<Users> 
<UserInfo> 
    <Name>ddd</Name> 
    <Wallet>0</Wallet> 
    <UserCart> 
    <Products_> 
     <MedicineProduct 
     Product_Name="sak" 
     Product_ID="0" 
     Price="0" 
     Quntity="0" 
     Image="" /> 
    </Products_> 
    </UserCart> 
</UserInfo> 

这里就是我坚持......

public static void Edit(UserInfo user, Products usercart) 
{ 
    XmlDocument doc = new XmlDocument(); 
    doc.Load(path); 
    XmlNode node = doc.SelectSingleNode(string.Format("//UserInfo[./Name/text()='{0}']", user.Name)); 
} 

找到指定的用户。我如何用新值替换整个UserCart节点?

回答

2

您可以尝试使用较新的XDocument API来使用XML及其XElement.ReplaceWith()方法。

var xml = "<Users><UserInfo><Name>Old Name</Name></UserInfo></Users>"; 
var document = XDocument.Parse(xml); 
var replacedNode = document.Descendants("UserInfo") 
          .SingleOrDefault(x => x.Descendants("Name") 
                .Single() 
                .Value == "Old Name"); 

// The code below uses C# 6.0 null propagation feature to handle 
// the case when replacedNode is null (not found in XML). 
// In case you use C# 5.x or lower, you can just check it in an IF statement 
replacedNode?.ReplaceWith(new XElement("UserInfo", 
             new XElement("Name", "New Name"))); 

Console.WriteLine(document.ToString()); 

更新(2016年1月14日)

下面是关于如何编写扩展方法来取代用户的购物车的快速样品。虽然这绝对是可行的,但我会避免混淆业务逻辑(用户购物车更新)和基础架构/数据层(序列化)。我宁愿看到用户对象从XML中被反序列化,更新,然后被序列化回来。

public static class XmlExtensions 
{ 
    public static XElement ToXElement(this object obj) 
    { 
     using (var memoryStream = new MemoryStream()) 
     { 
      using (TextWriter streamWriter = new StreamWriter(memoryStream)) 
      { 
       var xmlSerializer = new XmlSerializer(obj.GetType()); 
       xmlSerializer.Serialize(streamWriter, obj); 
       return XElement.Parse(Encoding.ASCII.GetString(memoryStream.ToArray())); 
      } 
     } 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var xml = "<Users><UserInfo><Name>Old Name</Name><UserCart></UserCart></UserInfo></Users>"; 

     var document = XDocument.Parse(xml); 

     var userCart = document.Descendants("UserInfo") 
      .SingleOrDefault(x => x.Descendants("Name").Single().Value == "Old Name") 
      ?.Element("UserCart"); 

     var newUserCart = new UserCart 
     { 
      Products = new List<Product> 
      { 
       new Product { Name = "First" }, 
       new Product { Name = "Second" } 
      } 
     }; 

     userCart?.ReplaceWith(newUserCart.ToXElement()); 

     Console.WriteLine(document.ToString()); 
    } 
} 

public class UserCart 
{ 
    public List<Product> Products { get; set; } 
} 

public class Product 
{ 
    public string Name { get; set; } 
    public int Quantity { get; set; } 
} 

正如我在评论中提到的,你也可以使用属性从System.Xml命名空间(例如XmlElement)来控制序列化。请注意,XmlSerializer有其局限性。例如,它不能将接口序列化出来。

+1

注意'?.'(空条件运算符)是C#6.0的一部分,所以如果OP使用VS 2013或更早运营商将无法使用。 – Tim

+0

你是对的。如果使用C#5.x或更低版本,则可以将'replacedNode'替换为'null'。更新了答案。 –

+1

我想用新值替换整个UserCart让与 有没有办法通过简单地传递UserCart对象 - 新的XElement(“UserCart”,usercart)))?或者我需要设置值UserCart的每个属性,如Product_Name =“New”等? –

0

这取决于你想要替换的东西。如果你只是想设定一些文字在里面,这是非常简单的:

XmlNode cart = doc.SelectSingleNode(string.Format("//UserInfo[./Name/text()='{0}']/UserCart", "ddd")); 
cart.InnerText = "Replaced!"; 

注意我改变你的选择,所以你会得到的实际车节点,而不是它的父。

如果你想用新的XML节点来取代它,你必须创建它们,将它们添加到文档,并添加他们:

XmlNode cart = doc.SelectSingleNode(string.Format("//UserInfo[./Name/text()='{0}']/UserCart", "ddd")); 
// clear out nodes 
cart.RemoveAll(); 
cart.AppendChild(doc.CreateNode(XmlNodeType.Element, "test", "")); 

与所有的说,它通常最好使用较新的XDocument API,它可能看起来像......

XDocument doc = XDocument.Parse(xml); 
//doc.LoadXml(xml); 

XElement cart = doc.Root.Descendants("UserCart").Where(x => (string)x.Parent.Element("Name") == "ddd").FirstOrDefault(); 
if (cart != null) 
    cart.ReplaceNodes(new XElement("test")); // or you can do cart.Value = "text" you're not adding new elements. 
相关问题