2009-10-01 2 views
6

XmlReader가 전달되는 메서드를 재정의했습니다. 특정 요소를 찾고 특성을 추가 한 다음 새 XmlReader를 만들거나 바꾸기 만하면됩니다. 수정 된 내용이있는 기존 항목 나는 C# 4.0을 사용 중이다.XmlReader - 요소를 편집하고 새 요소를 생성해야합니다.

XElement (Linq)를 사용하여 조사했지만 기존 요소를 조작하고 속성과 값을 추가 할 수 없다.

내가 XmlWriter를 환상적 일 것이다 WriteAttributeString을 가지고 있음을 알고 있지만 다시 내가 뭔가를 할 수 있도록하고 싶습니다 모두가 함께

에 맞는 방법을 잘 모르겠습니다 --- 이것은 의사 코드입니다!

public XmlReader DoSomethingWonderful(XmlReader reader) 
{ 
    Element element = reader.GetElement("Test"); 
    element.SetAttribute("TestAttribute","This is a test"); 
    reader.UpdateElement(element); 
    return reader; 
} 

답변

11

순차 액세스 스트림입니다 성가신 수 있습니다. 한쪽 끝을 읽고 스트림을 처리하고 다른 쪽 끝을 써야합니다. 이점은 모든 것을 메모리로 읽어 들일 필요가 없으며 XmlDocument 기반 접근 방식으로 얻을 수있는 DOM을 구축해야한다는 것입니다.

private static void PostProcess(Stream inStream, Stream outStream) 
{ 
    var settings = new XmlWriterSettings() { Indent = true, IndentChars = " " }; 

    using (var reader = XmlReader.Create(inStream)) 
    using (var writer = XmlWriter.Create(outStream, settings)) { 
     while (reader.Read()) { 
      switch (reader.NodeType) { 
       case XmlNodeType.Element: 
        writer.WriteStartElement(reader.Prefix, reader.Name, reader.NamespaceURI); 
        writer.WriteAttributes(reader, true); 

        // 
        // check if this is the node you want, inject attributes here. 
        // 

        if (reader.IsEmptyElement) { 
         writer.WriteEndElement(); 
        } 
        break; 

       case XmlNodeType.Text: 
        writer.WriteString(reader.Value); 
        break; 

       case XmlNodeType.EndElement: 
        writer.WriteFullEndElement(); 
        break; 

       case XmlNodeType.XmlDeclaration: 
       case XmlNodeType.ProcessingInstruction: 
        writer.WriteProcessingInstruction(reader.Name, reader.Value); 
        break; 

       case XmlNodeType.SignificantWhitespace: 
        writer.WriteWhitespace(reader.Value); 
        break; 
      } 
     } 
    } 
} 

이 자신의 XmlWriter를 도출하는 것만 큼 깨끗하지,하지만 난 훨씬 쉽게 찾을 :

이 방법을 사용하면 시작할 수 있습니다.

[편집]

이 같은 수 있습니다 한 번에 두 개의 스트림을 열 것입니다 방법의 예 :

using (FileStream readStream = new FileStream(@"c:\myFile.xml", FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write)) { 
    using (FileStream writeStream = new FileStream(@"c:\myFile.xml", FileMode.OpenOrCreate, FileAccess.Write)) { 
    PostProcess(readStream, writeStream); 
    } 
} 
1

쉽게 XmlReader으로이 작업을 수행 할 수 있습니다 - 적어도이 아닌, 독자로부터의 전체 XML 문서를 읽고 그것을 가지고 작업 후 결과에서 새 XmlReader을 만들지 않고. 그것은 XmlReader을 사용하는 것의 많은 포인트를 무너 뜨 렸습니다 - 즉, 큰 문서를 스트리밍 할 수있는 능력.

당신 수 잠재적으로 대부분의 방법은 기존의 독자에게 호출을 전달하지만, 적절한 등 추가 속성을 추가하도록 차단, XmlReader에서 파생 ...하지만 난 그 코드는 정말 매우 복잡하고 깨지기 쉬운 것 생각한다.

+0

답장을 보내 주셔서 감사합니다, 나는 (희망) 이것은 좋은 간단한 작업 것이라고 생각. XML을 특정 요소까지 읽어서 편집 한 다음 변경된 결과를 출력하고 싶은 유일한 사람은 아닙니다. - 오늘 독서에서 평소보다 맹세코 더 많이 듣는다면 .... 나야! –

+0

@Phill : 스트리밍 방식으로 작성하는 것이 쉽지 않습니다. ( –

+0

'XmlReader'를 서브 클래 싱하는 것 (추상적 인 메소드를 많이 구현하지 않는 한 실제로'XmlTextReader'를 서브 클래스화할 것입니다)은 흥미로운 도전. –

1

나는

+1

나는 그것이 작동하는지 확신하지 못할 것입니다. 반환하는 독자는 이 요소 다음에 요소로 이동할 수 있어야합니다 (실제로 원래 판독기가 처리하고있는 나머지 모든 XML 문서)는 해당 백업 스트림에 있지 않습니다. –

0

차라리 XmlDocument로 XML을로드하는 것을 선호합니다 .... 내가이 방법을 수행하기위한 더러운 느낌이 있지만,이 작동

public XmlReader FixUpReader(XmlReader reader) 
    { 
     reader.MoveToContent(); 

     string xml = reader.ReadOuterXml(); 

     string dslVersion = GetDSLVersion(); 
     string Id = GetID(); 

     string processedValue = string.Format("<ExampleElement dslVersion=\"{1}\" Id=\"{2}\" ", dslVersion, Id); 
     xml = xml.Replace("<ExampleElement ", processedValue); 
     MemoryStream ms = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(xml)); 
     XmlReaderSettings settings = new XmlReaderSettings(); 

     XmlReader myReader = XmlReader.Create(ms); 
     myReader.MoveToContent(); 
     return myReader; 
    } 

코딩 다음 덕트 테이프를 사용하여 고정 이 값을 업데이트하려면 Attributes 컬렉션을 사용하고 Save 메서드를 호출하십시오. 아래 코드는 나를 위해 작동합니다.

public static void WriteElementValue (string sName, string element, string value) 
{ 
    try 
    { 
    var node = String.Format("//elements/element[@name='{0}']", sName); 
    var doc = new XmlDocument { PreserveWhitespace = true }; 
    doc.Load(configurationFileName); 

    var nodeObject = doc.SelectSingleNode(node); 

    if (nodeObject == null) 
     throw new XmlException(String.Format("{0} path does not found any matching 
     node", node)); 

    var elementObject = nodeObject[element]; 

    if (elementObject != null) 
    { 
     elementObject.Attributes["value"].Value = value; 
    } 

    doc.Save(configurationFileName); 
} 
catch (Exception ex) 
{ 
    throw new ExitLevelException(ex, false); 
} 

}

당신이 XmlWriter를하거나 XmlSerializer를 공백이 제대로 보존되지 않은 사용할 때 내가 관찰 한이 때로는 XmlReader를/라이터

-2
 string newvalue = "10"; 
     string presentvalue = ""; 
     string newstr = ""; 
     XmlReader xmlr = XmlReader.Create(new StringReader(str)); 

     while (xmlr.Read()) 
     { 
      if (xmlr.NodeType == XmlNodeType.Element) 
      { 
       if (xmlr.Name == "priority") 
       { 
        presentvalue = xmlr.ReadElementContentAsString(); 
        newstr = str.Replace(presentvalue, newvalue); 
       } 
      } 

     } 

// newstr이 파일에 다시 기록 할 수 있습니다. ..즉, 편집 된 XML입니다

관련 문제