2016-01-14 43 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. 
相關問題