2012-03-08 2 views
0

XML을 업데이트하는 기능을 쓰고 있으며 몇 가지 문제가 있습니다. 이전 XElement를 업데이트 된 버전으로 직접 설정할 수는 있지만 foreach 루프에서는 작동하지 않습니다 (단 하나의 쿼리 결과 여야 함). 각 필드를 하드 코딩하려고했지만 루프를 사용하기로 결정했습니다. 이 섹션을 명중하고 하위 요소는 단일 요소로 모두를 읽고 그리고 파일을 엉망 그러나 때복잡한 XML로 데이터 업데이트

var myDevice = from c in appDataXml.Descendants("device") 
       where (string)c.Element("name") == App.CurrentDeviceName 
         && (string)c.Element("ip") == App.CurrentIp 
       select c; 

if (myDevice.Any()) 
{ 
    foreach (XElement device in myDevice) 
    { 
     //device.Element("customname").Value = updatedDevice.Element("customname").Value; 

     for (int a = 0; a < device.Elements().Count(); a++) 
     { 
      string field = device.Elements().ElementAt(a).Name.ToString(); 
      device.Element(field).Value = updatedDevice.Element(field).Value; 
     } 
    } 
} 

샘플 XML은

<Devices> 
    <device> 
    <name>blah</name> 
    <customname>custom</customname> 
    <ip>192.168.1.100</ip> 
    <port>1000</port> 
    <sources> 
     <source> 
     <code>00</code> 
     <name>blah2</name> 
     <hidden>False</hidden> 
     </source> 
     <source> 
     ...etc 
    </sources> 
    </device> 

답변

1

을 (만들기 클래스)를 사용하면 CRUD 및 검색에 도움이됩니다.

예 : (사용하여 이러한 확장 : http://searisen.com/xmllib/extensions.wiki)

public class Device 
{ 
    const bool ELEMENT = false; 
    const bool ATTRIBUTE = true; 

    XElement self; 
    public Device(XElement self) { this.self = self; } 

    public string CustomName 
    { 
     get { return self.Get("customname", string.Empty); } 
     set { self.Set("customname", value, ELEMENT); } 
    } 
    public string Name { get { return self.Get("name", string.Empty); } } 
    public string Ip { get { return self.Get("ip", "0.0.0.0"); } } 
    public int Port { get { return self.Get("port", 0); } } 

    public Source[] Sources 
    { 
     get { return _Sources ?? (_Sources = self.GetEnumerable("sources/source", xsource => new Source(xsource)).ToArray()); } 
    } 
    Source[] _Sources; 

    public class Source 
    { 
     XElement self; 
     public Source(XElement self) { this.self = self; } 

     public string Code { get { return self.Get("code", string.Empty); } } 
     public string Name { get { return self.Get("name", string.Empty); } } 
     public bool Hidden { get { return self.Get("hidden", false); } } 
    } 
} 

예는 그것을 사용 :

XElement xdevices = XElement.Load(file.FullName); 
Device[] devices = xdevices.GetEnumerable("device", xdevice => new Device(xdevice)).ToArray(); 
var myDevice = devices 
    .Where(d => d.Name == App.CurrentDeviceName 
       && d.Ip == App.CurrentIp); 

foreach (Device device in myDevice) 
{ 
    string name = device.Name; 
    foreach (Device.Source source in device.Sources) 
    { 
     string sourceName = source.Name; 
    } 
    device.CustomName = "new name"; 
} 
xdevices.Save(file.FullName); 

그것은 사고 방식의 변화, 그래서 대신 참조하는 방법에 대한 걱정의 값을 사용하면 XML에 대한 읽기/쓰기 클래스를 만들고 대신 클래스에 데이터를 가져 오거나 전달하여 xml을 읽고 씁니다.

편집 : 가 ----

파일과 일치하도록 ---- XElementConversions 클래스에 추가하고 내가 상세한 버전을 만들어 제대로 작동 할 수 있습니다. 당신은 XElement.Value Property를 사용하지 마십시오 등 부울, 날짜 시간,

public static int GetInt(this XElement source, string name, int defaultValue) 
{ 
    source = NameCheck(source, name, out name); 
    return GetInt(source, source.GetDefaultNamespace() + name, defaultValue); 
} 

public static int GetInt(this XElement source, XName name, int defaultValue) 
{ 
    int result; 
    if (Int32.TryParse(GetString(source, name, null), out result)) 
     return result; 
    return defaultValue; 
} 
+0

Windows Phone 7 프로젝트가 중요하다고 생각됩니다. Extender가 사용하는 TypeDescriptor가 구현되지 않은 것처럼 보입니다 – Jason

+0

직접 시도해 볼 수 있습니다. http : // msdn.microsoft.com/en-us/library/ayybcxe5.aspx –

+0

또는'GetString()'을 사용하는'GetInt()','GetBool()'등을 만들 수 있습니다. 예를 들어 int,'GetInt() {return Convert.ToInt32 (GetString (...)); } ' –

0

당신은 XElement.Value를 사용하지만 반복하지 말아야 장치 내의 XElement 요소를 XElement으로 변경하고 XText 노드를 변경하십시오. 또는 XAttribute을 사용할 수 있으므로 많은 중첩 요소를 만들 필요가 없습니다.

<Devices> 
<Device Name="blah" IP="192.168.1.100" Port="1000"> 
    <Sources> 
    <Source Code="00" Name="blah2" Hidden="false"/> 
    </Sources> 
</Device> 
</Devices> 

XElement.ValueXElement의 후손있는 모든 XText 노드의 연결된 문자열입니다. set 인 경우 결과적으로 모든 하위 요소를 덮어 씁니다. 자세히보기 XElement.Value

1

var myDevice = ... select c;은 최대 1 개의 요소를 생성합니까? 그래서 다음 .Single()에 구멍 .Any()foreach() 교체 할 경우

: 나는 이유를 볼

var myDevices = ... select c; 
var myDevice = myDevices.Single(); // exception when Count != 1 

그리고 왜이 작동하지 않을 : 당신은 추상적 인 필요

myDevice.Element("customname").Value = updatedDevice.Element("customname").Value; 
+0

그 라인이하는 일,하지만 각 필드, 즉 IP, 포트에 대한 행을 할 필요가 없습니다 것입니다, 그래서 나는 루프를했고, :

사용하는 대신 값이 줄을보십시오 소스 하위 항목 처리에 대한 확신이 없었습니다 – Jason

0

처럼 다른 종류를 만들기 위해 수정할 수 있습니다. XElement.ReplaceWith Method을 사용하십시오. 값의 게터 출력

이 요소의 텍스트 내용이 모두 포함 된 문자열. 텍스트 노드가 여러 개인 경우 연결됩니다.

이는 하위 요소의 태그가 제거된다는 것을 의미합니다. 그때

device.Element(field).ReplaceWith(updatedDevice.Element(field));