잊지 않겠습니다.

'Pro LINQ'에 해당되는 글 5건

  1. 2009.01.15 Pro LINQ (07)
  2. 2009.01.13 Pro Linq (06)
  3. 2009.01.09 Pro LINQ (05)
  4. 2009.01.09 Pro LINQ (04)
  5. 2009.01.08 Pro LINQ (03)

Pro LINQ (07)

Book 2009. 1. 15. 02:32
XML Schema(*.xsd)파일을 이용한 XML의 Validation과 기존의 XmlDocument에서 지원되는 XPath 역시 같이 지원 가능하다. 또한, 제공되는 XML을 통한 XML Schema를 역으로 얻어내는 방법을 같이 제공하고 있다. 

var xDocument = new XDocument();
var rootElement = new XElement("BookParticipants");

var bookElement1 = new XElement("BookParticipant");
bookElement1.Add(new XAttribute("type", "Author"));
bookElement1.Add(new XElement("FirstName", "Joe"));
bookElement1.Add(new XElement("LastName", "Rattz"));
rootElement.Add(bookElement1);

var bookElement2 = new XElement("BookParticipant");
bookElement2.Add(new XAttribute("type", "Editor"));
bookElement2.Add(new XElement("FirstName", "Ewan"));
bookElement2.Add(new XElement("LastName", "Buckingham"));
rootElement.Add(bookElement2);

xDocument.Add(rootElement);
xDocument.Save("bookparticipants.xml");

XmlSchemaInference infer = new XmlSchemaInference();
XmlSchemaSet schemaSet = infer.InferSchema(XmlReader.Create("bookparticipants.xml"));
XmlWriter xmlWriter = XmlWriter.Create("bookparticipants.xsd");

foreach(XmlSchema xmlSchema in schemaSet.Schemas())
{
    xmlSchema.Write(xmlWriter);
}
xmlWriter.Close();

XDocument schemaDocument = XDocument.Load("bookparticipants.xsd");
Console.WriteLine(schemaDocument);

정말로 대단한 기능이라고 생각이 되는 것이, XML 파일만 있더라고 그 안에서 XSD의 추론이 가능해지기 때문에, 그 응용을 어떤 방향으로 솔찍히 해줘야지 될지 잘은 모르겠다는 생각이 든다. 아직 XSD를 잘 사용을 안하고 있는 것이 잘 모르고 있는 이유중 하나일 것 같다.

XML의 Validation은 다음과 같이 할 수 있다. 기존의 XmlDocument와 코드가 완전히 동일하다.
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.Add(string.Empty, "bookparticipants.xsd");
try
{
    xDocument.Validate(schemaSet, null);
    Console.WriteLine("Document validated successfully");
}
catch(XmlSchemaValidationException ex)
{
    Console.WriteLine(ex.Message);
}


마지막으로 XDocument에서의 XPath 사용을 간략한 예이다.
xDocument.Add(rootElement);
XElement xElement = xDocument.XPathSelectElement("//BookParticipants/BookParticipant[FirstName='Joe']");
Console.WriteLine(string.Format("Selected Element : {0} / {1}", xElement.Name, xElement.Value));




Posted by Y2K
,

Pro Linq (06)

Book 2009. 1. 13. 10:51
LINQ를 이용한 XML의 검색방법 역시 기존의 LINQ와 동일하다. 
특징적으로 이야기할 수 있는 사항은 각각의 XML의 element, attribute, comment 등으로 검색이 가능하다는 점으로, DB LINQ나 Object LINQ에서 사용하는 것과 같이 XML의 특성으로 검색이 가능하다. 

조금 복잡한 LINQ query를 하나 예시로 든다면.. 

            var biddata = from b in bids.Descendants("bid_tuple")
                          where double.Parse(b.Element("bid").Value) > 50
                          join u in users.Descendants("user_tuple")
                              on b.Element("userid").Value equals u.Element("userid").Value
                          join i in items.Descendants("item_tuple")
                              on b.Element("itemno").Value equals i.Element("itemno").Value
                          select new
                                     {
                                         Item = b.Element("itemno").Value,
                                         Description = i.Element("description").Value,
                                         User = u.Element("name").Value,
                                         Date = b.Element("bid_date").Value,
                                         Price = b.Element("bid").Value
                                     };
            foreach(var bd in biddata)
            {
                Console.WriteLine("{0, -12} {1, -12} {2, -6}, {3, -14}, {4:C, 10}", bd.Date, bd.User, bd.Item,
                                  bd.Description, bd.Price);
            }

보면 재미있는 내용중 하나가 select 구문에서의 새로운 Class의 생성이다. 이 Class는 따로 선언되어있지 않으며, 각각의 Property의 이름을 각각 적어서 생성하게 된다. 이 부분은 C# 4.0에서 dynamic programming과 비슷하게 보이지만 dynamic으로 선언된것과는 다르게 사용된다. var로 선언되어 익명 class로 생성된 상태이다. 

여기에서 bd에 대해 type을 얻어보면 다음과 같다.
<>f__AnonymousType1`5[String, String, String, String, String]
사용된 Item, Description, User, Date, Price에 대해서 5개의 Property를 갖는 익명 Class의 선언으로 되어 있는 것을 알 수 있다.
Posted by Y2K
,

Pro LINQ (05)

Book 2009. 1. 9. 01:16
LINQ를 이용하면 XML의 검색 뿐 아니라, XML의 조작도 간단한 코드로 가능하다. 예전처럼 DataSet을 지정해서, DataSet에 Read Position을 잡아서 해주는 것이 아닌 직관적인 Method을 이용해서 XML의 조작이 가능하게 된다. 

기본적으로 사용되는 Method의 종류는 다음과 같다. 

추가 : Add(), AddFirst(), XNode.AddAfterSelft()
삭제 : Remove(), RemoveAll()
변경 : Update(), Replace(), ReplaceAll()

여기에서 재미있는 것이 ReplaceAll()의 경우인데, 모든 Element의 이름을 기준으로 값을 일괄적으로 변경이 가능하게 된다. 잘만 찾으면 재미있는 결과를 가지고 올 수 있을 것 같다. 

LINQ를 이용한 XML의 검색 및 변경에서 조금 특이한 경우가 XAttribute인데, XAttribute의 경우에는 W3C XML DOM API와 다르게 XAttribute를 통해서 이루어지게 된다. Element, Comment, Processing 과는 아주 약간 다른 조작을 행하게 되지만, 기본적으로 큰 차이는 존재하지 않는다. 

LINQ 및 기존의 XmlDocument에서 재미있는 내용중 하나는 각 Xml Element들에 대한 Event인데, XDocument에서도 기본적으로 Changing, Changed에 대해서 Event를 제공하고 있다. 

XDocument의 생성 및 변경을 통해서 재미있는 일을 할 수 있는데, 그 중 가장 재미있어보이기도 하고, 무엇보다 자주 사용할 수 있어보이는 XSLT transformation에 대한 재미있는 소스를 하나 적어보고 오늘 글을 마쳐볼려고 한다. ^^

XSLT :
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
<xsl:output method='html'/>
<xsl:template match='/'>
<html>
<head>
<title>Student Directory</title>
</head>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>

<xsl:template match='student_list'>
<h3>Student Directory for example.edu</h3>
<xsl:apply-templates />
</xsl:template>
<xsl:template match='name'>
<p>Name: <xsl:apply-templates /></p>
</xsl:template>
<xsl:template match='major'>
<p>Major: <xsl:apply-templates /></p>
</xsl:template>
<xsl:template match='phone'>
<p>Phone: <xsl:apply-templates /></p>
</xsl:template>
<xsl:template match='email'>
<p>Email: <xsl:apply-templates /></p>
</xsl:template>
</xsl:stylesheet>

XML : 
<student_list>
<student>
<name>John</name>
<major>Math</major>
<phone>010</phone>
<email>student1@mail.co.kr</email>
</student>
<student>
<name>Tom</name>
<major>English</major>
<phone>0001389</phone>
<email>student2@mail.co.kr</email>
</student>
</student_list>

이 둘에대한 transformation에 대한 소스는 다음과 같다. 
            XDocument xDocument = XDocument.Parse(xml);
            XDocument transformedDoc = new XDocument();
            using(XmlWriter xmlWriter = transformedDoc.CreateWriter())
            {
                XslCompiledTransform transform = new XslCompiledTransform();
                transform.Load(XmlReader.Create(new StringReader(xsl)));
                transform.Transform(xDocument.CreateReader(), xmlWriter);
            }
            Console.WriteLine(transformedDoc);


그리고 멋진 실행결과는 다음과 같다. ^^


이걸 이용하면 MailTemplate들이나 Table 표시 포멧을 만들어주는데 표준적인 방법을 제시할 수 있다. (당장 써보고 싶은 기능이다.)
Posted by Y2K
,

Pro LINQ (04)

Book 2009. 1. 9. 01:02
XML을 얻는다면 일반적으로 XmlDocument를 선언하고, XmlDocument에서 지정된 Node의 선택과 node에 대한 Tree 구조로 탐색을 하게 된다. 그러나, LINQ를 사용하게 될 경우에는 이러한 Tree 구조 탐색에 별 의미가 없게 된다. 

XElement에서 각 이름에 대한 검색 및 각 속성에 대한 검색을 모두 지원하고 있다. 다음 소스의 결과는 다음과 같다. 

        public void DoForAncestors()
        {

            XDocument xDocument = new XDocument(
                new XElement("BookParticipants",
                             new XElement("BookParticipant",
                                          new XAttribute("type", "Author"),
                                          new XElement("FirstName", "Joe"),
                                          new XElement("LastName", "Rattz")),
                             new XElement("BookParticipant",
                                          new XAttribute("type", "Editor"),
                                          new XElement("FirstName", "Ewan"),
                                          new XElement("LastName", "Buckingham"))));
            Console.WriteLine("Original XML : ");
            Console.WriteLine(xDocument.ToString());
            Console.WriteLine();
            Console.WriteLine("Search node : name == FirstName");
            var elements = xDocument.Element("BookParticipants").Descendants("FirstName");
            foreach(var element in elements)
            {
                Console.WriteLine(element.Value);
            }
        }



기존의 경우에는 모든 node의 트리 구조를 알고 있어서 xpath를 이용해서 SelectSingleNode 또는 SelectNodeList를 이용해서 각 값을 구해주었지만, LINQ를 이용하면, node에 대한 이름만을 이용해서 얻는 것이 가능하다. 그리고 얻어진 node에서 각 Parent를 얻어내는 것도 가능하다. 

여기에서 한가지 의문이 생기는 것이... 기존의 XmlDocument의 경우에는 거의 필요가 없는 class가 되어버리는 경향이 있는 것 같다. XmlDocument에서 이용하던 거의 모든 method들을 XDocument에서 제공하고 있으며, LINQ 및 보다더 선언적인 XML을 선언할 수 있는 것까지. 지금은 잘 모르겠지만.. 아무래도 XmlDocument를 앞으로는 사용할 일이 그다지 없지 않을까 라는 성급한 생각도 해보게 된다. (물론 .NET Framework 2.0에서의 경우는 또 다르다.;)

XML을 검색을 할때에 Element, Processing, Comment에 대한 검색을 하는 것 역시 LINQ에서 지원이 가능하다. 
또한 선언적인 Type을 넣어줄 수 있기 때문에 코드의 가독성 역시 같이 높아진다. 

        public void SearchForType()
        {
            XDocument xDocument = new XDocument(
                        new XElement("BookParticipants",
                         new XElement("BookParticipant",
                                      new XAttribute("type", "Author"),
                                      new XComment("This is XComment"),
                                      new XProcessingInstruction("Processing", "New Processing"),
                                      new XElement("FirstName", "Joe"),
                                      new XElement("LastName", "Rattz")),
                         new XElement("BookParticipant",
                                      new XAttribute("type", "Editor"),
                                      new XElement("FirstName", "Ewan"),
                                      new XElement("LastName", "Buckingham"))));
            Console.WriteLine(xDocument.ToString());
            Console.WriteLine();

            var elements = xDocument.Element("BookParticipants").
                Elements("BookParticipant").Nodes().OfType<XComment>();

            foreach(var element in elements)
            {
                Console.WriteLine(element);
            }
        }



Posted by Y2K
,

Pro LINQ (03)

Book 2009. 1. 8. 00:28
먼저 설명된 select, take 등이 지연된 operation이라면, 모든 Action이 호출즉시 나오게 된다. 이럴 경우에는 LINQ가 가진 속도의 장점을 잃어버리게 된다. 그렇지만 모든 객체를 한번에 얻어와서 일을 처리하게 될 경우에는 보다더 용의하게 된다. 

    public class DataContextLinq
    {
        public void QueryDatas()
        {
            NorthwindDataContext dbContext = new NorthwindDataContext(@"Data Source=Y2K\SQLEXPRESS;Initial Catalog=AdventureWorks;Integrated Security=True");
            dbContext.Log = Console.Out;

            Console.WriteLine("Queried datas - Start");
            var products = (from p in dbContext.Products where p.Color == "Red" select p.Name).ToList();
            Console.WriteLine("Queried datas - End");
            
            Console.WriteLine("Deferred Operation - Start");
            foreach(string productName in products)
            {
                Console.WriteLine(productName);
            }
        }
    }

결과는 다음과 같다. 

차이를 보면, 값을 얻어오는 순간 모든 Query가 실행이 되고, 전 값을 다 얻어오게 된다. 
nondeferred operation은 다음과 같다. 

ToArray()
ToList()
ToDictionary()
ToLookup()
First()
FirstOrDefault()
LastOrDefault()
Single()
SingleOrDefault()
ElementAt()
Sum()
Max()
Min()
etc.... 


경우에 따라 deferred operation과 non-deferred operation의 사용을 달리해줄 필요가 있다. 많은 양의 데이터를 가지고 온다면 deferred operation이 속도 면에서 더 나은 선택이 되지만, 많은 데이터에 대해서 일괄처리를 하게 될 경우에는 non-deferred operation이 선택이 될 수 있다. 











Posted by Y2K
,