목차
msdn에서 읽고 있는 xml 프로그래밍 : 설명이 시작 페이지
<color silver>뻑 XML, 그냥 맘편하게 JSON 쓰자고…</color>
개념 설명
Xml DOM
from : XML DOM, msdn
<?xml version="1.0"?> <books> <book> <author>Carson</author> <price format="dollar">31.95</price> <pubdate>05/01/2001</pubdate> </book> <pubinfo> <publisher>MSPress</publisher> <state>WA</state> </pubinfo> </books>
이 xml은 아래 그림처럼 메모리에 구조화 된다.
- 각 원은 XmlNode 개체 - DOM 트리에서 기본 개체
- XmlDocument (extended from XmlNode)로 메모리 로드/파일저장 (문서작업)을 수행 가능
- DOM을 사용한 구조적인 접근/편집이 필요없이, 단순 읽기/쓰기가 필요한 경우
- price는 특성(Attribute)이 있으며, GetAttribute를 사용해서 값을 읽어 올 수 있다.
주요 클래스의 자식 유무의 차이
- 있음 : Document / DocumentFragment / EntityReference / Element / Attribute
- 없음 : XmlDeclaration / Notation / Entity / CDATASection / Text / Comment / ProcessingInstruction / DocumentType
XmlNode(XmlDocument)로 가능한 작업
- 노드 액세스 및 수정 / 정보 검색
- 전체 노드 검색 / 노트가 포함하는 정보 검색
- 메모리 상에서 작업
그외
다른 접근 방식
- 순차 접근 : XmlReader/XmlWriter 를 사용한 순차(Front to Back) 탐색 방식 사용 가능
- 임의 접근 : XPath / XPathNavigator
노드 형식
XmlNode로부터 얻을 수 (쓸 수 있는) 노드 형식 msdn,Xml 노드형식에 나와 있다.
일부 발췌
DOM 노드 형식 | 개체 | 설명 |
---|---|---|
Document | XmlDocument | Document 루트. 하지만 루트요소와 동일하진 않다, 무슨 말이지? |
DocumentFragment | XmlDocumentFragment | 트리구조 없이, 하나 이상 노드 포함하는 임시 노드 |
Element | XmlElement | 요소 노드 |
Attr | XmlAttribute | 요소노드의 특성 |
Text | XmlText | 요소,특성의 텍스트 |
닷넷 전용 노드 형식
노드 형식 | 설명 |
---|---|
XmlDeclaration | <?xml version=“1.0”…> 선언 노드 |
XML DOM 계층 구조
이걸 보면, 상하 관계가 좀 더 확실히 보여진다.
전체 트리와 무관한 단독 클래스
- XmlImplementation : xml문서 만드는데 사용.
- XmlNamedNodeMap : 정렬되지 않은 노드 검색
- XmlNodeList : 인덱스별로 정렬된 노드 검색
- XmlNodeChangedEventArgs : xml문서 이벤트 처리, 좀 알아둬야할 것 같은 느낌
XML 데이터에 개체 계층 구조 매핑
이거 좀 옮기기 어렵다. 원본 참조
<book> <title>The Handmaid's Tale</title> </book>
- book : XmlElement
- title : XmlElement
- The Handmaid's Tale : XmlText
각 노드 타입에 따라, 연결되는 개체 클래스가 달라지므로 NodeType을 확인해서 맞게 사용 해야 한다.
예제에서 사용된 타입, 타입 확인은 XmlNodeType 개체를 사용하고 if문이나 switch를 사용해서 비교 가능
XmlNodeType.Element |
XmlNodeType.Text |
XmlNodeType.CDATA |
XmlNodeType.ProcessingInstruction |
XmlNodeType.Comment |
XmlNodeType.XmlDeclaration |
XmlNodeType.EntityReference |
XmlNodeType.EndElement |
오퍼레이션
문서 만들기
읽기/쓰기 어느 쪽을 하든 시작은 이렇게
XmlDocument doc = new XmlDocument();
읽으려는 경우,
- Load 메소드를 사용해서 읽기
- XmlReader를 사용해서 로드
- LoadXML 메서드를 사용해서 읽기
- 선택은? 글쎄 아직 모르겠음.
문서 읽기
- XmlReader : 여러 형식(문자열/스트림/URL/텍스트판독기)으로 부터 XML을 읽어옴
- Load : 문서를 메모리로 읽어 옮
- LoadXml : 문자열에서 xml을 읽어옴
LoadXml을 사용해 메모리상의 xml로드
xml 기본 형식을 정할 수 있다면, 아래 예처럼 미리 더미값을 포함한 xml을 LoadXml로 읽어 들인 다음, 값을 수정하는 것도 괜찮겠다.
using System; using System.IO; using System.Xml; public class Sample { public static void Main() { // Create the XmlDocument. XmlDocument doc = new XmlDocument(); doc.LoadXml("<book genre='novel' ISBN='1-861001-57-5'>" + "<title>Pride And Prejudice</title>" + "</book>"); // Save the document to a file. doc.Save("data.xml"); } }
노드 추가
다음 오퍼레이션이 가능
DOM에서 새 노드 만들기의 경우, 각 노드요소 별로 생성 메소드가 있으므로 그걸 사용하면 된다. 도움말에 보면 아래 항목이 보인다.
특성을 추가하려는 경우 (또 다른 링크라서, 링크만 건다.) msdn은 온라인 문서라 그런지 depth가 너무 많다.
XmlNodeChangedEventArgs를 사용한 XML 문서의 이벤트 처리
XmlNodeChangedEventArgs를 사용한 XML 문서의 이벤트 처리
노드에 어떤 작업(추가/삭제/변경)이 발생될때 이벤트가 발생된다. (어디에 쓰는건지는 잘 모르겠음)
이벤트 | 발생 시기 |
---|---|
NodeInserting | 현재 문서에 속한 노드가 다른 노드에 삽입되기 직전 |
NodeInserted | 현재 문서에 속한 노드가 다른 노드에 삽입된 후 |
NodeRemoving | 이 문서에 속한 노드가 문서에서 제거되기 직전 |
NodeRemoved | 이 문서에 속한 노드가 부모로부터 제거된 직후 |
NodeChanging | 노드 값이 변경되기 직전 |
NodeChanged | 노드 값이 변경된 직후 |
XML 문서에서 노드, 내용 및 값 수정
- XmlNode
- .Value : 값 변경
- .InnerXml : 노드 전체 변경 (노드를 새 노드로 바꾸기). 자식노드의 태그를 변경.
- .RemoveChild : 기존 노드를 삭제 (삭제된 노드를 리턴)
- XmlCharacterData (문자열 처리)
- .AppendData / InsertData
- .ReplaceData 로 문자열 처리. 원래값이 리턴값으로 돌아옴.
- .DeleteData : 범위내 문자열 제거
변경 가능한 노드 형식은 정해져 있으며, 범위 밖의 노드에서 변경 시도시 예외 발생
- InvalidOperationException
변경 가능한 노드 형식
노드 형식 | 변경되는 데이터 |
---|---|
Attribute | 특성 값 |
CDATASection | CDATASection 내용 |
Comment | 주석 내용 |
ProcessingInstruction | 대상을 제외한 내용 |
Text | 텍스트 내용 |
XmlDeclaration | <?xml 및 ?> 태그를 제외한 선언 내용 |
Whitespace | 공백 값.인식된 XML 공백 문자인 공백, 탭, CR 또는 LF 중 하나로 값을 설정할 수 있습니다. |
SignificantWhitespace | 유효 공백 값.인식된 XML 공백 문자인 공백, 탭, CR 또는 LF 중 하나로 값을 설정할 수 있습니다. |
XPath 탐색
XPath Select
- SelectSingleNode : 선택 기준과 일치하는 첫번째 노드
- SelectNodes : 일치하는 노드들의 XmlNodeList를 리턴
네임스페이스를 포함할 수 있다(아래 예제처럼)라고 msdn에 명시. 없는 경우는 어떻게 되는지 모르겠네..
네임스페이스가 없는 경우, 해당 구문 없이 사용
- 있음 : “descendant::bk:book[bk:author/bk:last-name='Kingsolver']”
- 없음 : “descendant::book[author/last-name='Austen']”
// Load the document and set the root element. XmlDocument doc = new XmlDocument(); doc.Load("bookstore.xml"); XmlNode root = doc.DocumentElement; // Add the namespace. XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable); nsmgr.AddNamespace("bk", "urn:newbooks-schema"); // Select and display the first node in which the author's // last name is Kingsolver. XmlNode node = root.SelectSingleNode( "descendant::bk:book[bk:author/bk:last-name='Kingsolver']", nsmgr); Console.WriteLine(node.InnerXml);
<?xml version='1.0'?> <bookstore xmlns="urn:newbooks-schema"> <book genre="novel" style="hardcover"> <title>The Handmaid's Tale</title> <author> <first-name>Margaret</first-name> <last-name>Atwood</last-name> </author> <price>19.95</price> </book> <book genre="novel" style="other"> <title>The Poisonwood Bible</title> <author> <first-name>Barbara</first-name> <last-name>Kingsolver</last-name> </author> <price>11.99</price> </book> <book genre="novel" style="paperback"> <title>The Bean Trees</title> <author> <first-name>Barbara</first-name> <last-name>Kingsolver</last-name> </author> <price>5.99</price> </book> </bookstore>
XML 데이터 형식 변환
XmlConvert 클래스의 메서드를 사용해서 형식 변환을 한다.
날짜형식
// example : <Element>2001-02-27T11:13:23</Element> DateTime vDateTime = XmlConvert.ToDateTime(reader.ReadString());
상세한 내용 (변경 가능 부분) : 문자열을 .NET Framework 데이터 형식으로 변환
예제
xml을 메모리에 저장하고 사용
using System.Xml; using System.Xml.XPath; namespace XXX { class EMailDataXml { XmlDocument mDoc; public EMailDataXml() { mDoc = new XmlDocument(); // save this to memory mDoc.LoadXml( @"<queue>" + @"<info index=""-1"" handler=""QICmd1""/>" + @"<email>" + @"<addr>dummy@x.y.z</addr>" + @"<title>n/a</title>" + @"<text>nothing</text>" + @"</email>" + @"</queue>" ); // insert header XmlDeclaration xmldecl; xmldecl = mDoc.CreateXmlDeclaration( "1.0", "UTF-8", "yes" ); XmlElement rootNode = mDoc.DocumentElement; mDoc.InsertBefore( xmldecl, rootNode ); } // XPath로 XmlNode를 찾아서, Attribute에 값을 추가 public void updateIndex( int newIndex ) { try { XmlNode targetNode = mDoc.SelectSingleNode( "queue/info" ); if( targetNode == null || targetNode.Attributes == null ) return; XmlAttributeCollection _attrCol = targetNode.Attributes; XmlAttribute _attrIndex = (XmlAttribute)_attrCol.GetNamedItem( "index" ); _attrIndex.Value = newIndex.ToString(); } catch( XPathException _exp1 ) { System.Windows.Forms.MessageBox.Show( _exp1.ToString() ); } } public void updateHandler( string handlerName ) { try { XmlNode targetNode = mDoc.SelectSingleNode( "queue/info" ); if( targetNode == null || targetNode.Attributes == null ) return; XmlAttributeCollection _attrCol = targetNode.Attributes; XmlAttribute _attrHandlerName = (XmlAttribute)_attrCol.GetNamedItem( "handler" ); _attrHandlerName.Value = handlerName; } catch( XPathException _exp1 ) { System.Windows.Forms.MessageBox.Show( _exp1.ToString() ); } } // XPath로 XmlNode를 찾은 뒤, 하위 노드들을 순서대로 읽어서 값을 변경 public void updateEMailData( string addr, string title, string emailText ) { try { XmlNode targetParentNode = mDoc.SelectSingleNode( "queue/email" ); if( targetParentNode == null ) return; // get first child XmlNode _child = targetParentNode.FirstChild; // set value and move to next sibling xmlNode _child.FirstChild.Value = addr; _child = _child.NextSibling; _child.FirstChild.Value = title; _child = _child.NextSibling; _child.FirstChild.Value = emailText; } catch( XPathException _exp1 ) { System.Windows.Forms.MessageBox.Show( _exp1.ToString() ); } } } }