'XML'에 해당되는 글 12건

Programming/.NET

AJAX를 따로 구현하지 않고 만들어진 일반적인 경우는 서버로 부터 특정 페이지의 모든 컨텐츠를 내려받아 화면에 표시하는 방법이 될것입니다.

 

public class Member
{
    public string Name { getset}

    public string Email { getset}

    public DateTime BirthDay { getset}
    public int Point { getset}

    public MemberType MT { getset}
}

public enum MemberType
{
    Admin,
    Normal,
    Guest
}

▶ Model

 

public class HomeController : Controller
{
    Member[] mb = {
        new Member() { Name = "홍길동"Email = "hong1@cliel.com"Point = 100, BirthDay = new DateTime(1981, 11, 14)MT = MemberType.Guest },
        new Member() { Name = "홍길남"Email = "hong2@cliel.com"Point = 110, BirthDay = new DateTime(1980, 4, 23)MT = MemberType.Admin },
        new Member() { Name = "홍길석"Email = "hong3@cliel.com"Point = 55, BirthDay = new DateTime(1973, 8, 19)MT = MemberType.Normal },
        new Member() { Name = "홍길순"Email = "hong4@cliel.com"Point = 80, BirthDay = new DateTime(1992, 6, 5)MT = MemberType.Normal },
        new Member() { Name = "홍길영"Email = "hong5@cliel.com"Point = 98, BirthDay = new DateTime(1986, 3, 8)MT = MemberType.Normal }
    };

    // GET: Home
    public ActionResult Index()
    {
        return View(mb);
    }

    [HttpPost]
    public ActionResult Index(string mt)
    {
        if (string.IsNullOrEmpty(mt))
            return View(mb);
        else {
            MemberType MT = (MemberType)Enum.Parse(typeof(MemberType)mt);
            return View(mb.Where(x => x.MT == MT));
        }
    }
}

▶ Controller

 

@using WebApplication1.Classes
@model IEnumerable<WebApplication1.Classes.Member>

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div>
        <table border="1">
            <thead><tr><th>이름</th><th>포인트</th><th>생년월일</th></tr></thead>
            @foreach (Member m in Model) {
                <tr>
                    <td>@m.Name</td>
                    <td>@m.Point</td>
                    <td>@m.BirthDay.ToString("yyyy년MM월dd일")</td>
                </tr>
            }
        </table>
    </div>
    <br />
    @using (Html.BeginForm()) {
        @Html.DropDownList("mt"EnumHelper.GetSelectList(typeof(MemberType))"전체"new { @class = "form-control" })
        <input type="submit" value="확인" />
    }
</body>
</html>

▶ Index View

 

이 예제는 AJAX없는 일반적인 방법으로 View의 DropDownList로 표시된 항목중 원하는 항목을 선택하고 '확인'버튼을 누르면 HttpPost속성이 설정된 액션메서드로 선택한 타입이 전달되어 Where확장메서드를 통해 필터링된 Member의 리스트를 표시합니다. 여기서 주목해야할 부분은 Member의 리스트를 다시 받아오는 방식인데 현재는 View에 존재하는 모든 컨텐츠를 일괄적으로 받아오고 있습니다.

 

컨텐츠의 양이 작아 사실 이정도 트래픽이 발생하는 것은 부담스러운게 아니지만 View에 이미지나 CSS, JAVA Script파일등이 같이 존재하는 페이지면 단순히 명단을 불러오기위해 페이지 전체를 새로고침하게 되고, 이는 모든 컨텐츠를 처음부터 새로 받아와야 하는 비효휼적인 동작방식으로 연결됩니다.

 

이런 문제를 해결하기 위한 방법중 하나로 우리는 AJAX를 사용할 수 있습니다. AJAX는 Asynchronous JavaScript and XML로서 비동기로 서버와 통신해 필요한 내용만을 XML포멧으로 수신하여 웹페이지에 반영하는 기술입니다. 이것은 페이지의 새로고침을 유도하지 않고 페이지상에 필요한 부분만을 바꿀 수 있는 방법이 됩니다.

 

웹프로그램에 AJAX를 구현하려면 우선 NuGet 패키지 관리자를 통해 JQuery와 Microsoft.Jquery.Unobtrusive.Ajax 패키지를 설치해야 합니다.

 

 

패키지를 설치하고 나면 프로젝트의 Script 폴더에 몇가지 스크립트 파일이 추가되는데 이중에서 2가지 스크립트를 AJAX구현이 필요한 페이지에 다음과 같이 추가하도록 합니다.

 

<head>

    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="~/Scripts/jquery-3.1.1.js"></script>
    <script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
</head>

 

그런다음 본래 데이터를 받아오는 액션메서드를 자식액션메서드로 수정하여 데이터처리를 자식액션메서드에서 처리할 수 있도록 합니다.

 

public PartialViewResult GetMember(string mt)
{
    if (string.IsNullOrEmpty(mt))
        return PartialView(mb);
    else {
        MemberType MT = (MemberType)Enum.Parse(typeof(MemberType)mt);
        return PartialView(mb.Where(x => x.MT == MT));
    }
}

 

그리고 기존 Index 액션메서드를 수정해야 하는데 이는 Index View에서 더이상 Member의 열거타입에 대한 처리를 수행하고 있지 않기에 부분뷰로 필터링할 문자열넘 넘겨주는 구조가 되어야 하기 때문입니다.

 

public ActionResult Index()
{
    return View((object)string.Empty);
}

 

그런다음 자식액션에 맞는 부분뷰를 만들어 기존에 Index뷰에 있던 foreach부분을 그대로 옮겨놓습니다.

 

@using WebApplication1.Classes
@model IEnumerable<WebApplication1.Classes.Member>

@foreach (Member m in Model) {
    <tr>
        <td>@m.Name</td>
        <td>@m.Point</td>
        <td>@m.BirthDay.ToString("yyyy년MM월dd일")</td>
    </tr>
}

▶ GetMember.cshtml 부분뷰

 

Member를 표시하는 부분을 부분뷰로 이동시키고 나면 기존의 Index뷰에서는 기존 표시부분을 부분뷰로 대체할 수 있도록 다음과 같이 변경해야 합니다.

 

@using WebApplication1.Classes
@model string

@{
    Layout = null;

    AjaxOptions ao = new AjaxOptions { UpdateTargetId = "memberBody" };
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="~/Scripts/jquery-3.1.1.js"></script>
    <script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
</head>
<body>
    <div>
        <table border="1">
            <thead><tr><th>이름</th><th>포인트</th><th>생년월일</th></tr></thead>
            <tbody id="memberBody">
                @Html.Action("GetMember"new { mt = Model })
            </tbody>
        </table>
    </div>
    <br />
    @using (Ajax.BeginForm("Getmember", ao)) {
        @Html.DropDownList("mt"EnumHelper.GetSelectList(typeof(MemberType))"전체"new { @class = "form-control" })
        <input type="submit" value="확인" />
    }
</body>
</html>

 

본문에 foreach로 Member를 표시하는 부분을 자식뷰를 통해 가져올 수 있도록 하였습니다. 또한 기존 Html.BeginFrom을 Ajax로 대체하여 DropDonList의 선택항목을 자식액션메서드인 GetMember로 전송하게 하고 AjaxOptions 의 인스턴스를 함께 전달하고 있습니다.

 

따라서 DropDownList 에서 원하는 항목을 선택하고 폼을 제출하는 버튼인 '확인'을 누르면 서버측에 데이터를 요청하고 그 결과를 화면의 새로고침이 없이 즉각적으로 갱신할 것입니다. 만약 버튼대신 특정 링크를 통해 AJAX동작을 수행하고자 한다면 BeginForm대신 ActionLink 메서드를 통해 다음과 같이 링크를 생성할 수 있습니다.

 

@Ajax.ActionLink("Guest""GetMember"new { mt = "Guest" }, ao)

 

AjaxOptions는 또한 여러 속성을 지정하여 AJAX동작을 수행할때 필요한 다양한 설정을 동반할 수 있습니다. 예를 들어 Confirm은 AJAX동작을 수행하기전 사용자에게 확인메세지를 표시하는 용도로 사용될 수 있으며 UpdateTargetId 는 서버로 부터 수신된 내용을 표시할 HTML영역에 대한 ID를 지정할 수 있습니다.

 

@{
    Layout = null;

    AjaxOptions ao = new AjaxOptions { UpdateTargetId = "memberBody"Confirm = "Memer를 불러 오시겠습니까?" };
}

 

이렇게 AJAX를 구현하고 나면 페이지를 새로고침하지 않고도 표현된 데이터를 갱신할 수 있게 되었습니다. 그런데 만약 요청하려는 데이터를 가져오기까지 시간이 많이 걸리는 경우 사용자 입장에서는 그냥 화면이 정지해 있는 상태로 보여질 수 있기 때문에 서버측에 데이터를 요청하면 화면이 갱신되기 까지 적절한 메세지를 표시할 필요가 있을 것입니다.

 

이를 위해 우선 사용자에게 필요한 메세지 영역을 만들고

 

<body>

    <div id="loading" style="display:none">
        기다려 주십시오.
    </div>
    <div>
        <table border="1">
            <thead><tr><th>이름</th><th>포인트</th><th>생년월일</th></tr></thead>
            <tbody id="memberBody">
                @Html.Action("GetMember"new { mt = Model })
            </tbody>
        </table>
    </div>
    <br />
    @using (Ajax.BeginForm("GetMember", ao)) {
        @Html.DropDownList("mt"EnumHelper.GetSelectList(typeof(MemberType))"전체"new { @class = "form-control" })
        <input type="submit" value="확인" />
    }
</body>

 

AjaxOptions 개체의 속성을 다음과 같이 설정합니다.

 

AjaxOptions ao = new AjaxOptions { UpdateTargetId = "memberBody"Confirm = "Memer를 불러 오시겠습니까?"LoadingElementId="loading"LoadingElementDuration=1000 };

 

LoadingElementId 는 메세지 영역을 만들어둔 html 요소의 id값을 지정하며 LoadingElementDuration 에는 해당 영역이 애니메시션형식으로 표시될 시간을 지정합니다. 이렇게 하면 서버에 데이터를 요청할때마다 메세지가 존재하는 div영역이 1초간 서서히 화면에 표시될 수 있습니다.

 

AJAX를 통해 서버에 데이터를 요청하고 응답된 데이터를 가져와 화면에 갱신시키는 과정에서 필요하다면 콜백메서드를 활용해 특정 처리를 수행할 수도 있습니다. 예를 들어 작업이 완료된 경우 사용자에게 '완료'라는 메세지를 보여주고 싶다면 아마도 다음과 같이 처리할 수 있을 것입니다.

 

<script type="text/javascript">
    var OnComplete = function (req, status) {

            alert('완료됨');
        };
</script>

 

우선 위와 같이 콜백으로 호출될 메서드를 생성하고

 

AjaxOptions ao = new AjaxOptions
{
    UpdateTargetId = "memberBody",
    LoadingElementId = "loading",
    LoadingElementDuration = 1000,
    OnComplete = "OnComplete"
};

 

해당 메서드를 AjaxOptions 개체에 설정하면 모든 작업이 완료되었을때 OnComplete 메서드를 자동으로 호출할 것입니다. 이 외에도 처리시작전 호출되는 메서드는 OnBegin, 작업실패시 호출되는 메서드는 OnFailure, 작업성공시 호출되는 메서드는 OnSuccess 속성을 통해 설정하면 됩니다.

 

특히 OnSuccess 메서드는 매개변수로 서버로부터 응답되어 오는 데이터를 받을 수 있는데 이를 이용하면 AJAX의 응답을 JSON으로 처리하려고 할때 해당 데이터를 적절히 처리할 수 있는 방안을 제공합니다.

 

public JsonResult GetMemberJson(string mt)
{
    if (string.IsNullOrEmpty(mt))
        return Json(mb);
    else
    {
        MemberType MT = (MemberType)Enum.Parse(typeof(MemberType)mt);
        return Json(mb.Where(x => x.MT == MT));
    }
}

 

서버로 부터의 결과를 JSON으로 받고자 한다면 우선 JsonResult 형식을 반환하는 액션메서드를 생성해야 합니다. 또한 액션 메서드는 내부에서의 반환을 Json메서드로 처리하여 데이터를 JSON 포멧으로 반환할 수 있도록 처리합니다.

 

@using (Ajax.BeginForm("GetMemberJson", ao)) {
    @Html.DropDownList("mt"EnumHelper.GetSelectList(typeof(MemberType))"전체"new { @class = "form-control" })
    <input type="submit" value="확인" />
}

 

그런 다음 Form에서의 데이터 요청이 위에서 작성한 GetMemberJson으로 갈 수 있도록 하고

 

<script type="text/javascript">
    var OnSuccess = function (data) {
        $('#memberBody').empty();

        for (var i = 0; i < data.length; i++) {
            var date = new Date(parseInt(data[i].BirthDay.substr(6)));
            $('#memberBody').append('<tr><td>' + data[i].Name + '</td><td>' + data[i].Point + '</td><td>' + date.getFullYear() + '년' + date.getMonth() + '월' + date.getDay() + '일' + '</td></tr>');
        }
    };
</script>

 

OnSuccess 메서드에서 data를 인자로 받아 이전과 동일하게 보여질 수 있도록 스크립트를 통해 처리합니다. 이때 data는 JSON포멧형태로 반환되어 오는 데이터가 될것입니다.

 

AjaxOptions ao = new AjaxOptions
{
    UpdateTargetId = "memberBody",
    LoadingElementId = "loading",
    LoadingElementDuration = 1000,
    OnSuccess = "OnSuccess"
};

 

그리고 AjaxOptions 개체에 OnSuccess 메서드를 지정하면 JSON으로 데이터 포멧을 다룰 수 있는 모든 처리가 완료됩니다.

 

하지만 스크립트를 통해서 데이터를 처리하다보니 다소 코드가 장황해지는 상황이 발생할 수 있는데 예제에서는 Member의 BirthDay를 처리하기 위해 getFullYear나 getMonth처럼 각 날짜에 해당하는 메서드를 일일이 호출하여 날짜형식의 포멧을 맞추려고 하고 있습니다. 물론 굳이 이렇게 하지 않아도 되지만 이런 형태의 장황함은 얼마든지 존재할 수 있으며 이러한 문제는 액션메서드에서 다음과 같이 필요한 필드의 포멧을 맞추어 줌으로서 해결할 수 있습니다.

 

public JsonResult GetMemberJson(string mt)
{
    if (string.IsNullOrEmpty(mt))
        return Json(mb);
    else
    {
        MemberType MT = (MemberType)Enum.Parse(typeof(MemberType)mt);
        return Json(mb.Where(x => x.MT == MT).Select(x => new { Name = x.NamePoint = x.PointBirthDay = x.BirthDay.ToString("yyyy년MM월dd일") }));
    }
}

 

참고로 예제에서는 UpdateTargetId 속성이 여전히 존재하는데 이 속성은 수정된 현재의 상황에는 필요없는 속성이므로 제거되어도 프로그램에는 아무런 영향을 끼치지 않습니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET MVC] 번들(Bundle)  (0) 2018.01.02
[C#] nameof  (0) 2017.12.27
[ASP.NET MVC] AJAX  (0) 2017.12.22
[C#] Assembly  (0) 2017.12.13
[C#] LINQ  (0) 2017.12.05
[C#] 문자열 보간 ($)  (0) 2017.11.28
0 0
Programming/.NET

웹서비스를 이용하면 SOAP(Simple Object Access Protocol)를 통해 이기종간에 XML통신을 통하여 필요한 정보를 전달할 수 있습니다.

 

웹서비스를 생성하려면 Add New Item 대화상자에서 Web Service(ASMX) 를 선택하고 'Add'버튼을 누릅니다.

 

 

 

웹 서비스를 추가하고 나면 asmx확장자의 파일이 하나 생성되는데 해당 cs파일의 내용은 대략 아래와 같거나 비슷할 것입니다.

 

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
// [System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService
{

    [WebMethod]
    public string HelloWorld()
    {
        return "Hello World";
    }
}

 

WebService 특성은 네임스페이스를 의미합니다. 예제에는 URL이 기재되어 있는데 URL이 들어간 특별한 이유는 없고 그냥 원하는 내용을 기입하면 됩니다. 중요한건 '유일한 값'이여야 한다는 것인데 대부분 URL을 사용하는 이유는 http://www.cliel.com/tmpnamespace/i 와 같이 기재하면 유일성을 가질 수 있기 때문입니다.(기재된 URL은 그냥 네임스페이스를 의미하는 '값'일뿐 실제 존재하는가는 중요하지 않습니다.)

 

참고로 WebService에는 Name과 Description 특성을 사용할 수도 있는데

 

[WebService(Namespace = "http://tempuri.org/", Name ="test")]

 

여기에는 각각 웹서비스의 이름과 설명을 담을 수 있습니다.

 

WebServiceBinding은 XML웹 서비스가 구현된 버전을 의미하며 WsiProfiles.BasicProfile1_1은 WS-I Basic Profile 1.0을 준수하고 있다는 것을 말해주고 있습니다.

 

하단의 주석처리된 부분은 AJAX 스크립트에 필요한 내용으로서 필요하다면 그냥 주석을 지우면 됩니다.

 

예제에서는 웹서비스 메소드로 HelloWorld 메소드가 구현되어 있는데 이 메소드에는 WebMethod라는 특성이 존재하며 해당 특성에는 다음과 같은 내용의 속성을 지정할 수 있습니다.

 

 BufferResponse

 이 속성을 true로 설정하면 웹서비스의 응답내용이 메모리에 저장되어 클라이언트에 전송됩니다.

 CacheDuration

 응답내용이 캐시처리되는 시간을 설정합니다. 기본값은 0인데 사용하지 않음을 의미합니다. 입력은 초단위이며 int형의 값을 받습니다.

 Description

 웹서비스 메소드의 설명부분입니다.

 EnableSession

 해당 메소드의 세션기능을 사용하고자 하는 경우 true로 설정합니다.

 TransactionOption

 이 속성값을 true로 설정하면 좀 복잡하지만 내부에 또다른 웹서비스를 호출하는 식으로 2개 이상의 웹서비스가 교차적으로 동작할때 도중 장애가 발생하면 각 처리과정이 롤백되도록 트랜잭션기능을 켤 수 있습니다.

 

위와같이 웹서비스를 만들고 나면 이제 클라이언트에서는 해당 웹서비스를 호출하여 원하는 정보를 얻을 수 있게 됩니다. 웹이든 응용이든 상관없이 또 다른 프로젝트를 하나 생성하여 위에서 만들어 놓은 웹서비스를 호출해 보도록 하겠습니다.

 

생성한 프로젝트의 Solution Explorer창에서 해당 프로젝트를 마우스 오른쪽 클릭하여 Add -> Service Reference 항목을 선택합니다.

 

 

 

Address에 접근가능한 웹서비스의 URL을 입력하고 'Go'버튼을 눌러줍니다. 그러면 해당 웹서비스에 존재하는 메소드를 표시하게 됩니다. 메소드가 확인되면 'OK'버튼을 눌러 프로젝트에 웹서비스항목을 추가합니다.

 

private void button2_Click(object sender, EventArgs e)
{
    ServiceReference.testSoapClient test = new ServiceReference.testSoapClient();
    label1.Text = test.HelloWorld();
}

 

지금 예제에서는 응용프로그램 프로젝트를 생성하고 버튼과 Label컨트롤을 배치한뒤 웹서비스를 위와같이 호출하였습니다. 보시는 바와 같이 웹서비스를 호출하는 방법은 아주 간단합니다.

 

이제 웹서비스가 구현된 곳으로 다시 돌아가 보겠습니다. 예제에서는 HelloWorld라는 메소드가 하나 존재했었는데 실제 웹서비스를 구현하다보면 같은 이름의 메소드를 여러개 만들어 이를 오버로드해야할 경우가 발생합니다.

 

[WebMethod]
public string HelloWorld()
{
    return "Hello World";
}

[WebMethod]
public string HelloWorld(string name)
{
    return "Your Name : " + name + "Hello World";
}

 

하지만 위와 같이 하는것만으로는 불가능하고 WebMethod특성에 MessageName속성을 추가하여 해당 속성값을 달리설정해야 합니다.

 

[WebMethod(MessageName ="Hello1")]
public string HelloWorld()
{
    return "Hello World";
}

[WebMethod(MessageName ="Hello2")]
public string HelloWorld(string name)
{
    return "Your Name : " + name + "Hello World";
}

 

이때 하나더 고려해야할 부분이 있습니다. 위와같이 MessageName속성을 추가하고 나면 WebServiceBinding에 표시되어 있는 WS-I Basic Profile 1.0 명세를 제거해야 합니다. 해당 명세는 웹메소드의 오버로드를 허용하지 않기 때문입니다.

 

[WebServiceBinding(ConformsTo = WsiProfiles.None)]

 

웹서비스는 기본적으로 내부의 데이터를 외부에 공개하기 위한 용도로 사용됩니다. 하지만 그렇다 하더라도 특정 클라이언트에 해당하는 사용자만을 대상으로 웹서비스를 공개해야 하는 경우가 생길 수 있습니다. 예를 들어 접근해 오는 클라이언트는 자신만의 아이디와 암호를 사용해 웹서비스를 사용하도록 할때 아이디와 암호를 전달하여 클라이언트의 인증여부를 처리하는 것입니다.

 

이런 경우 우리는 SOAP Header를 사용하여 웹서비스를 구현할 수 있습니다. 우선 SOAP Header를 구현하기 위한 클래스를 다음과 같이 생성합니다.

 

public class tmpSoapHeader : System.Web.Services.Protocols.SoapHeader
{
    public string user_name;
    public string user_password;
}

 

참고로 해당 클래스는 웹서비스영역과 같은 위치에 있어야 하며 SoapHeader클래스를 상속받아야 합니다. 이제 위에서 작성한 클래스는 웹서비스안에 인스턴스로 만들고 SoapHeader특성을 추가하여 해당 인스턴스이름을 전달하도록 합니다. 그러면 실제 코드안에서 인스턴스를 통해 원하는 속성에 접근이 가능합니다.

 

public class WebService : System.Web.Services.WebService
{
    public tmpSoapHeader tsh;

    [WebMethod]
    [SoapHeader("tsh")]
    public string HelloWorld()
    {
        if (tsh == null)
            return "사용자 인증 실패";

        if (tsh.user_name == "administrator" && tsh.user_password == "1234")
            return "사용자 인증 성공";
        else
            return "사용자 인증 실패";
    }
}

public class tmpSoapHeader : System.Web.Services.Protocols.SoapHeader
{
    public string user_name;
    public string user_password;
}

 

클라이언트에서는 기존에 참조한 웹서비스의 형태가 변경되었으므로 그대로 사용할 수 없고 대신 해당 웹서비스를 마우스 오른쪽 클릭하여 'Update Service Reference'를 선택해 웹서비스기능을 업데이트해야 합니다.

 

그러면 웹서비스에서 추가된 Header클래스를 통해 필요한 정보를 대입하고 웹메소드 호출시 해당 헤더정보를 전달할 수 있습니다.

 

private void button2_Click(object sender, EventArgs e)
{
    ServiceReference.tmpSoapHeader tsh = new ServiceReference.tmpSoapHeader();
    ServiceReference.testSoapClient test = new ServiceReference.testSoapClient();

    tsh.user_name = "administrator";
    tsh.user_password = "1234";

    label1.Text = test.HelloWorld(tsh);
}

 

참고로 해당 웹서비스를 비동기로 호출하려고 시도하면 비동기에 필요한 몇몇 메소드가 존재하지 않음을 알 수 있습니다. 이는 웹서비스를 참조할때 일반운영모드로 웹서비스를 참조했기 때문입니다. 웹서비스의 웹메소드를 비동기로 처리하려면 최초참조시 Add Service Reference 대화상자에서 Advenced... 버튼을 눌러 Generate asynchronous operations를 선택하고 참조해야 합니다.

 

ServiceReference.tmpSoapHeader tsh = new ServiceReference.tmpSoapHeader();
ServiceReference.testSoapClient test = new ServiceReference.testSoapClient(); tsh.user_name = "administrator";
tsh.user_password = "1234";

IAsyncResult ar = test.BeginHelloWorld(tsh, null, null);

while (!ar.IsCompleted)
    label1.Text = "대기중...";

label1.Text = test.EndHelloWorld(ar);

 

웹서비스를 비동기로 호출할 수 있도록 참조하고 나면 위와 같이 웹메소드를 비동기로 호출할 수 있게 됩니다.

 

비동기 호출에서는 자동으로 생성되는 Begin-과 End-메소드를 사용하며 IAsyncResult 개체를 통해 대기상태를 판단할 수 있습니다. 이 개체의 IsCompleted속성이 true라면 EndHelloWorld메소드를 호출하여 즉시 메소드수행 결과를 받아올 수 있습니다.

'Programming > .NET' 카테고리의 다른 글

[C#] 이니셜라이저(initializer)  (0) 2016.10.11
[ASP.NET] 설정파일 - 1  (0) 2016.10.04
[ASP.NET] 웹서비스(Web Service)  (0) 2016.09.27
[ASP.NET] URL 매핑 (URL 라우팅)  (0) 2016.09.21
[ASP.NET] TreeView  (0) 2016.09.13
[ASP.NET] WCF - 2  (0) 2016.09.07
0 0
Programming/.NET

XSLT는 간단히 말해 기존 XML구조를 바꾸는 언어로서 XSLT파일을 생성한 뒤 XslCompiledTransform 클래스로 변환을 시도하면 XSLT에 정의된 구조대로 XML이 변환되는 것입니다.

 

이런 동작을 구현하기 위해 우선 다음과 같은 XML파일을 만들어 둡니다.

 

<?xml version="1.0"?>
<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/2001 books.xsd">
  <book id="bk101">
    <author>Gambardella, Matthew</author>
    <title>XML Developer's Guide</title>
    <genre>Computer</genre>
    <price>44.95</price>
    <publish_date>2000-10-01</publish_date>
    <description>
      An in-depth look at creating applications
      with XML.
    </description>
  </book>
  <book id="bk102">
    <author>Ralls, Kim</author>
    <title>Midnight Rain</title>
    <genre>Fantasy</genre>
    <price>5.95</price>
    <publish_date>2000-12-16</publish_date>
    <description>
      A former architect battles corporate zombies,
      an evil sorceress, and her own childhood to become queen
      of the world.
    </description>
  </book>
  <book id="bk103">
    <author>Corets, Eva</author>
    <title>Maeve Ascendant</title>
    <genre>Fantasy</genre>
    <price>5.95</price>
    <publish_date>2000-11-17</publish_date>
    <description>
      After the collapse of a nanotechnology
      society in England, the young survivors lay the
      foundation for a new society.
    </description>
  </book>
</catalog>

 

위 XML파일을 토대로 다음과 같은 구조의 XML을 도출하고자 합니다.

 

▶ 결과1-1

 

따라서 우선 위 구조에 해당하는 XSLT파일을 생성해야 하는데 Visual Studio의 Solution Explorer에서 새로운 아이템으로 xslt파일추가하도록 합니다.

 

 

그런다음생성된 xslt파일을 수정하여 원하는 구조를 정의하도록 합니다.

 

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="@* | node()">
    <xsl:element name="">
      <xsl:apply-templates select="//book"></xsl:apply-templates>
    </xsl:element>
  </xsl:template>
  <xsl:template match="book">
    <xsl:element name="제목">
      <xsl:value-of select="title"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

 

xslt는 변환대상이 되는 xml파일의 요소에 대응하는 템플릿구조로 이루어 집니다. 잠깐 위 xslt구조를 설명드리면 최상위 루트를 '책'으로 하고 <xsl:apply-templates select="//book"></xsl:apply-templates구문으로 xml의 book요소를 순회하도록 합니다. 이때 사용된 //book는 XPath식과 동일한 방식입니다. 그리고 순회중 발견된 book요소를 템플릿으로 정의한 '제목'이름의 요소아래 xml의 title요소값을 표시하도록 합니다.

 

또한 하위 요소선택시 //book와 동일하게 title/xxx 처럼 XPath식을 사용할 수 있으며 만약 xml에서가 아니라 직접 정의한 특정한 내용을 출력해야 하는 경우 <xsl:text>hi!!</xsl:text> 식으로 작성하도록 합니다.

 

XML과 XSLT파일이 준비되어 있으니 이제 실제 변환을 수행해야 하는데 이때는 XslCompiledTransform클래스를 사용합니다. XslCompiledTransform클래스는 2.0부터 새로 등장한 클래스로서 기존 1.1시절의 XslTransform클래스를 대체합니다

 

Response.ContentType = "text/xml";

string xslt_file = Server.MapPath("books.xslt");
string xml_file = Server.MapPath("books.xml");

XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xslt_file);

XPathDocument xpd = new XPathDocument(xml_file);

xslt.Transform(xpd, new XmlTextWriter(Response.Output));

 

우선 XslCompiledTransform클래스의 객체를 생성하여 Load메소드로 위에서 작성된 xslt파일을 로드합니다. 그리고 XPathDocument클래스로 xml파일을 불러들여 XSLT의 Transform메소드를 호출해 해당 xml파일에 대한 변환을 수행합니다.

 

XslCompiledTransform클래스를 사용할때는 XmlDocument보다는 꼭 XPathDocument클래스를 사용해야 하는데 이유는 xslt파일안에 XPath가 구현되어 있기 때문입니다. XSLT안에서 XPath가 작동하는데는 XPathDocument가 사용되며 성능또한 훨등히 빠르게 동작합니다.

 

참고로 클래스사용시 new XslCompiledTransform(true)처럼 bool값을 true로 전달하고 Visual Studio에서 종단점을 설정해 보면 xslt파일이 처리되는 과정을 디버깅할 수 있습니다.

 

다시 결과1-1로 돌아가보면 보여지는 형태가 XML형식임을 알 수 있습니다. 하지만 XSLT파일을 변경하면 웹과 조화를 이룰 수 있는 HTML로도 출력이 가능합니다.

 

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="html" indent="yes"/>
  <xsl:template match="@* | node()">
    <table border="1">
      <tr>
        <th>책 목록</th>
      </tr>
      <xsl:apply-templates select="//book"></xsl:apply-templates>
    </table>
  </xsl:template>
  <xsl:template match="book">
    <tr>
      <td>
        <xsl:value-of select="title"/>
      </td>
    </tr>
  </xsl:template>
</xsl:stylesheet>

 

XSLT에서 output method를 html로 바꾸고 템플릿에서 출력될 HTML를 위 예제와 같이 작성하기만 하면 됩니다.

 

참고로 이전 예제에서는 XML형식의 표시를 위해 aspx페이지에서 모든 HTML요소를 제거하고 cs코드에서 ContentType을 text/xml로 지정했는데 위 결과처럼 HTML형식으로 데이터를 표현하려면 HTML요소를 복구하고 text/xml지정구문을 제거해야 합니다.

 

또한 cs코드상에서 여전히 xml와 xslt파일을 읽고 출력하도록 했다면 결과표시의 위치가 다소 이상해 보일 수 있는데

 

 

 

동작구조상 cs단의 처리가 우선시 되어 나타나는 결과일 뿐입니다. 원하는 요소에 정확히 표시하려면 다음과 같이 XML컨트롤을 활용하시기 바랍니다.

 

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Xml ID="Xml1" runat="server" DocumentSource="~/books.xml" TransformSource="~/books.xslt" ></asp:Xml>
    </div>
    </form>
</body>
</html>

 

XslCompiledTransform클래스가 XSLT파일을 로드하면 이 파일에 대한 어셈블리를 생성한 후 처리를 진행하게 됩니다. 이렇게 해도 정상적으로 처리가 되지만 성능상 문제가 생겼다면 미리 XSLT에 대한 어셈블리를 생성하고 해당 dll을 참조하여 처리를 진행하는 것이 좋습니다. 이때 어셈블리 생성은 XSLTC 명령어를 사용합니다.

 

Visual Studio의 명령창을 열고 다음과 같이 xsltc명령을 내려주십시오.

 

 

xslt파일은 필요하다면 a.xslt b.xslt b.xslt 처럼 연속해서 나열할 수 있으며 마지막에 생성하고자 하는 어셈블리를 /out:-.dll 형식으로 넘겨주면 됩니다.

 

이제 생성된 dll을 Visual Studio 프로젝트에서 참조하고

 

 

코드를 다음과같이 바꿔줍니다.

 

Response.ContentType = "text/xml";

string xml_file = Server.MapPath("books.xml");

XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(typeof(books));

XPathDocument xpd = new XPathDocument(xml_file);
xslt.Transform(xpd, new XmlTextWriter(Response.Output));

 

프로그램은 이제 파일이 아닌 dll 어셈블리에서 XSLT에 대한 데이터를 가져올 것입니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] 예외처리  (0) 2016.05.11
[ASP.NET] 사이트 네비게이션 (sitemap)  (0) 2016.04.19
[ASP.NET] XSLT  (0) 2016.04.05
[ASP.NET] 공급자 모델 - 3  (0) 2016.03.30
[ASP.NET] 공급자 모델 - 2  (0) 2016.03.22
[ASP.NET] 공급자 모델 - 1  (0) 2016.03.17
0 0
Programming/.NET

 1. DataSet 과 XML

 

기본적으로 DataSet의 데이터를 XML로 표시하는건 간단합니다.

 

using (SqlConnection conn = new SqlConnection(con)) {
    SqlCommand cmd = new SqlCommand("Select * From BOOK;", conn);
    conn.Open();

    DataSet ds = new DataSet();
    ds.DataSetName = "books";
    ds.Load(cmd.ExecuteReader(), LoadOption.OverwriteChanges, "book");

    Response.ContentType = "text/xml";
    ds.WriteXml(Response.OutputStream);
}

 

DataSetName은 XML에 대응해 최상위노드에 해당합니다. 그리고 Load메소드의 마지막 인자로 전달한 book은 TableName을 지정하는 것인데 XML에서는 최상위노드 하위의 개별요소로 작용합니다. 그 다음 마지막에 WriteXml 메소드를 호출하여 DB로부터 읽어들인 Table개체를 XML로 표시하도록 하였습니다.

 

 2. XmlDataDocument

 

XmlDataDocument클래스는 DataSet클래스에서 작성된 XML에 대해 좀더 구체적이고 유연한 컨트롤방법을 제공하는 클래스입니다.

 

using (SqlConnection conn = new SqlConnection(con)) {
    SqlCommand cmd = new SqlCommand("Select * From BOOK;", conn);
    conn.Open();

    DataSet ds = new DataSet();
    ds.DataSetName = "books";
    ds.Load(cmd.ExecuteReader(), LoadOption.OverwriteChanges, "book");

    XmlDataDocument xdd = new XmlDataDocument(ds);
    XmlNodeList xnl = xdd.SelectNodes("//books/book/title");

    foreach (XmlNode xn in xnl)
        Response.Write(xn.InnerText + "<br />");
}

 

XmlDataDocument 클래스의 생성자로 DataSet을 넘겨주면 XmlDocument API로 DataSet의 XML접근을 가능하게 하며 인자로 넘겨준 DataSet을 기반으로한 XmlDataDocument의 DataSet을 제공하기도 합니다.

 

XmlDataDocument xdd = new XmlDataDocument(ds);
XmlNodeList xnl = xdd.SelectNodes("//books/book/title");

xdd.DataSet.EnforceConstraints = false;
foreach (XmlNode xn in xnl)
    xn.InnerText = "이건 제목";

foreach (DataRow dr in ds.Tables[0].Rows)
    Response.Write(dr[2].ToString() + "<br />");

 

이전 예제는 단순히 XML로 데이터를 불러와 보여주는데 그쳤지만 위 예제는 직접 XML의 데이터를 바꾸는 동작을 수행합니다. 이게 재미있는게 일단 DataSet을 통해 XmlDataDocument객체를 생성하면 해당 객체와 인자로 넘겨준 DataSet이 연결된다는 것입니다. 그래서 XML데이터를 바꾸면 그 값이 DataSet에도 그대로 반영됩니다. 다만 실제 데이터를 바꾸려면 XmlDataDocument클래스의 EnforceConstraints를 true로 설정해야 합니다.

 

xdd.DataSet.EnforceConstraints = false;
foreach (XmlNode xn in xnl) {
    xn.InnerText = "이건 제목";

    DataRow dr = xdd.GetRowFromElement((XmlElement)xn.ParentNode);
    Response.Write(dr[2].ToString() + "<br />");
}

 

변경된 데이터는 직접 DataSet 데이터를 순회하여 확인할 수 있고 아니면 XML노드를 다시 DataSet의 Row객체로 변환해 바로 보는것도 가능합니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] Calender  (0) 2016.03.07
[ASP.NET] DataList  (0) 2016.03.03
[ASP.NET] XML - 6  (0) 2016.02.23
[ASP.NET] XML - 5  (0) 2016.02.18
[ASP.NET] XML - 4  (0) 2016.02.11
[ASP.NET] XML - 3  (0) 2016.02.01
0 0
Programming/.NET

 1. XML 직렬화 (XmlSerializer)

 

XmlSerializer는 XML 데이터에서 원하는 값에 대해 특정 클래스(Class)로 CLR개체를 생성하는 직렬화를 수행할 수 있습니다.

 

우선 아래와 같이 간단한 클래스 하나를 추가합니다.

 

[XmlRoot(ElementName = "book")]
public class book_titleAndgenre
{
    [XmlElement(ElementName = "title")]
    public string title;
    [XmlElement(ElementName = "genre")]
    public string genre;
}

 

이 클래스는 title과 genre속성에 ElementName 특성을 추가해 XML의 어떤 요소값이 대상이 되는지를 알려주고 있습니다. 이렇게 해두면 샘플 XML에서 book요소를 기준으로 title과 genre값을 가져와 클래스로 직렬화 할 것입니다.

 

NameTable nt = new NameTable();
object book = nt.Add("book");

xrs.NameTable = nt;

XmlSerializerFactory xsf = new XmlSerializerFactory();

using (XmlReader reader = XmlReader.Create(xml_file, xrs)) {
    while (reader.Read()) {
        if (reader.NodeType == XmlNodeType.Element && book.Equals(reader.LocalName)) {
            XmlSerializer xs = xsf.CreateSerializer(typeof(book_titleAndgenre));
            book_titleAndgenre bt = (book_titleAndgenre)xs.Deserialize(reader.ReadSubtree());
            Response.Write(bt.title + ":::" + bt.genre + "<br />");
        }
    }
}

 

NameTable에 book요소를 추가하여 XML데이터를 검색합니다. XML데이터 순회도중 book에 해당하는 요소를 만나면 우선 위에서 생성한 클래스형태의 직렬화개체를 생성하고 ReadSubtree 메소드를 통하여 하위 모든 요소를 가져와 역직렬화를 통해 해당 클래스에 속성을 추가하게 됩니다.

 

ReadSubtree 메소드는 Read 메소드와 비슷하게 현시점에서 하위 모든 XML을 순회하도록 하지만 Read는 bool 타입을 반환하는 반면 ReadSubtree는 새로운 XmlReader개체를 생성합니다.

 

XmlSerializerFactory 클래스의 CreateSerializer 메소드는 Type개체를 인자값으로 받는데 이 인자로 전달한 개체는 어셈블리형태로 생성될 수 있는 개체여야 하기 때문에 직렬화의 대상이 클래스가 되는 것입니다.(참고로 클래스로 직렬화되는 대상은 public 속성만을 대상으로 합니다.)

 

 2. Linq를 사용한 CLR 개체생성

 

CLR개체를 생성하는 거라면 Linq를 사용해 위에서 보다 더 간단히 구현할 수 있습니다.

 

string xml_file = Server.MapPath("books.xml");

XDocument xd = XDocument.Load(xml_file);

var titleAndgenre = from book in xd.Descendants("book")
                    select new book_titleAndgenre
                    {
                        title = book.Element("title").Value,
                        genre = book.Element("genre").Value
                    };

foreach (book_titleAndgenre bt in titleAndgenre)
    Response.Write(bt.title + ":::" + bt.genre + "<br />");

 

Linq를 사용하는 방법은 실제 읽어들인 XML에서 select 구문으로 원하는 부분의 데이터를 읽어오도록 처리합니다. 위에서 보여진 예제와는 사뭇 다른데 특정 데이터값만을 대상으로 하는 Linq쿼리를 직접 다루게 되므로 직렬화나 역질화에 필요한 클래스를 사용하지 않습니다.

 

그렇다 보니 기존 클래스와의 타입 대조절차가 빠지게 되므로 개체생성 대상이 되는 클래스조차 별다른 특성없이 간단하게 작성될 수 있습니다.

 

public class book_titleAndgenre
{
    public string title;
    public string genre;
}

 

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] XML - 5  (0) 2016.02.18
[ASP.NET] XML - 4  (0) 2016.02.11
[ASP.NET] XML - 3  (0) 2016.02.01
[ASP.NET] XML - 2  (0) 2016.01.26
[ASP.NET] XML - 1  (0) 2016.01.18
[ASP.NET] Command Object  (0) 2016.01.13
0 0
Programming/.NET

 

 1. NameTable

 

NameTable은 XML요소를 개체참조형식으로 담아두는데 사용됩니다. 예를 들어 XML데이터를 순회하면서 다음과 같이 특정 요소를 문자열로 비교해서 처리해야 하는 경우라면

 

if (reader.NodeType == XmlNodeType.Element && reader.LocalName.Trim() == "title") {

 대신 NameTable 클래스를 사용하여 비교자체를 개체참조 형태로 대신할 수 있습니다. 이것은 단순히 문자열을 비교하는 것보다 일정이상 성능향상을 기대할 수 있게 합니다.

 

string xml_file = Server.MapPath("books.xml");
string xml_schema = Server.MapPath("books.xsd");

XmlReaderSettings xrs = new XmlReaderSettings();
xrs.IgnoreComments = true;
xrs.IgnoreWhitespace = true;

xrs.Schemas.Add(null, xml_schema);
xrs.ValidationType = ValidationType.Schema;
xrs.ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags.ReportValidationWarnings;
xrs.ValidationEventHandler += xrs_ValidationEventHandler;

NameTable nt = new NameTable();
object book = nt.Add("title");

xrs.NameTable = nt;

using (XmlReader reader = XmlReader.Create(xml_file, xrs)) {
    while (reader.Read()) {
        if (reader.NodeType == XmlNodeType.Element && book.Equals(reader.LocalName)) {
            while (reader.Read()) {
                if (reader.NodeType == XmlNodeType.Text) {
                    Response.Write(reader.Value + "<br />");
                    break;
                }
            }
        }
    }
}

▶ ex 1-1

 

NameTable 클래스에서 특정 객체를 생성한 다음 Add메소드를 호출하여 XML요소인 title 추가를 시도합니다. Add 메소드는 XML요소의 title과 동일한 title 개체참조를 반환하게 되고 Equals메소드를 통해 두개체의 동일성을 확인하게 되는 것입니다.

 

작은 XML의 경우에는 모르지만 대용량일 수록 성능향상을 기대할 수 있습니다. 게다가 NameTable은 다른 XML개체에서 재사용이 가능합니다.

 

 2. 데이터타입 변환

 

XML을 파싱할때 특정 데이터타입으로 XML요소의 값을 가져와야 하는 경우라면 XmlReader 클래스 개체에서 ReadElementContentAsXXX 형태의 메소드를 사용하면 됩니다. 예를 들어 이전 1-1 예제에서는 XML값을 가져오기 위해 reader.Value 처름 사용했다면 이것을 다음과 같이 바꿀 수도 있습니다.

 

Response.Write(reader.ReadElementContentAsString() + "<br />");

예제는 값을 String 테이터타입 형식으로 가져오지만 만일 정수나 기타 숫자를 통해 합계등을 구해야 하는 경우라고 가정할때

 

int.Parse(reader.Value)

기존에 위와 같이 형변환등을 수행했다면 대신 ReadElementContentAsInt() 메소드로 정수형태의 값을 가져오는 것입니다.

 

int i = reader.ReadElementContentAsInt()

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] XML - 4  (0) 2016.02.11
[ASP.NET] XML - 3  (0) 2016.02.01
[ASP.NET] XML - 2  (0) 2016.01.26
[ASP.NET] XML - 1  (0) 2016.01.18
[ASP.NET] Command Object  (0) 2016.01.13
[ASP.NET] DLL 교체 시 웹서비스 지연현상  (0) 2015.08.07
0 0
Programming/.NET
XML 컨트롤은 지정한 XSLT 에 따라 XML 파일을 제어하는 컨트롤입니다.
<asp:Xml ID="Xml1" runat="server" DocumentSource="~/sample.xml" TransformSource="XSLTFile1.xslt"></asp:Xml>
 주요속성/이벤트

1. DocumentSource

소스로 제공될 XML 파일을 지정합니다.

2. TransformSource

XML 변환을 위한 XSLT 파일을 지정합니다. XML 에 대해 별다른 파싱규약이 필요하지 않는 경우 이 속성은 제외될 수 있습니다.

DocumentSource 와 TransformSource 속성을 코드에서 구현하려면 다음과 같이 할 수 있습니다.
XPathDocument xpd = new XPathDocument(Server.MapPath("~/sample.xml"));
Xml1.XPathNavigator = xpd.CreateNavigator();

XslTransform xct = new XslTransform();
xct.Load(Server.MapPath("~/XSLTFile1.xslt"));
Xml1.Transform = xct;

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] FileUpload  (2) 2014.01.20
[ASP.NET] DropDownList  (0) 2014.01.16
[ASP.NET] XML (컨트롤)  (0) 2014.01.15
[ASP.NET] RadioButton  (0) 2014.01.14
[ASP.NET] AdRotator  (0) 2014.01.13
[ASP.NET] ListBox  (0) 2014.01.08
0 0
Programming
IT업계에서 가장 자주 쓰이는 말중의 하나로 XML을 빼놓을 수 없습니다. 도데체 XML이란 무엇일까요?

XML이란 Extensible Markup Language약자로 확장 Markup언어를 의미합니다. 대표적인 Markup언어로 HTML이란 것이 있습니다. Internet Homepage등을 만들때 기본 골격이 되는 언어로서 여기서 쓰이는 <font>나 <table> Tag는 이미 각 Tag마다 그 의미와 용도가 정해져 있습니다. 예를 들어 <font color="red">hello</font>라고 한다면 hello라는 문자열의 표시를 붉은 색으로 지정하겠다는 의미가 되죠.

이때 내가 hello라는 문자열을 빨간색으로 표시하기 위해 <글자 색상="빨간색">으로 임의의 Tag를 정해서 쓰게 되면 결코 hello글자는 붉은색으로 표시되지 않습니다. 그것은 이미 글자의 속성을 변경하기 위해 <font>등의 Tag를 써야한다는 규칙이 정해져 있기 때문입니다.

반면 XML은 Extensible이 의미하듯이 '확장'이 가능한 언어라고 할 수 있습니다. 이는 어떠한 목적을 위해 특정한 Tag만을 써야한다는 개념에서 벗어나 나 자신 스스로가 특정 Tag를 정하고 그 Tag에 의미를 부여하여 사용할 수 있다는 것을 의미합니다.

예를 들어 자동차와 비행기에 대한 정보를 XML을 통해 규정지으려고 할때 자동차를 의미하는 Tag는 무엇을 쓸지 비행기를 의미하는 Tag는 무엇을 쓸지 알아서 정하기만 하면 되는 것입니다.

<?xml version="1.0" encoding="euc-kr"?>
<tran>
 <car>똥차</car>
 <air>보잉747</air>
</tran>

운송수단을 의미하는 Tag로 <tran>태그를 정했으며 여기에 자동차는 <car>로 비행기는 <air> Tag를 정의하였습니다. 이처럼 XML은 어떤 특정한 Tag만을 써야한다는 약속이 없습니다. 부여하고자 하는 Tag를 마음껏 정의하고 사용하기만 하면 되는 것입니다.

이렇게 정의된 XML문서는 보통 확장자를 xml로 해서 문서로 저장하며 작성된 문서를 다른 매체(사람이나 Software등등..)에 전달할때는 각 Tag가 무엇을 의미하는지 그리고 어떻게 처리하면 좋을지에 대한 약속을 정하기만 하면 됩니다.

이는 XML이 어디서든 통하는 범용언어로서의 역활을 하기 때문에 가능한 것입니다. 앞어 말씀드린 HTML과 같은 경우는 Tag가 이미 정해져 있기 때문에 HTML만으로 특정한 정보를 상호간에 전달하기에는 부족한 점이 많을 것입니다.

예를 들어 보겠습니다. 단순히 검은색자동차, 흰색자동차라는 정보를 전달하고 싶지만 HTML은 이 정보를 규정짓는 Tag가 존재하지 않기 때문에 표현이 불가능 합니다. 하지만 XML은 정보를 의미하는 특정한 Tag를 만들어 부여하면 되므로 상호간에 해당 Tag에 대한 정의만 약속되어 있으면 원하는 정보의 전달이 가능하게 됩니다.

1. XML 작성 규칙

XML은 각각의 Tag에 대한 구체적인 정보를 스스로 구현하고 정의할 수 있지만 그렇다 하더라도 작성하는 문법사항까지 무시하고 마음대로 작성할 수는 없습니다.

문법이라고 해도 어렵거나 그다지 복잡한것은 없으므로 대략적으로만 알아보도록 하겠습니다.

(1) XML문서의 시작시에는 작성되는 XML의 버전과 인코딩정보를 기술합니다.

<?xml version="1.0" encoding="euc-kr"?>

(2) XML문서작성시 전체를 포괄하는 최상위 Tag는 하나만 있어야 합니다.

<?xml version="1.0" encoding="euc-kr"?>
<tran>
 <car>똥차</car>
 <air>보잉747</air>
</tran>
<cyl>
 <auto>뽈뽈이</auto>
</cyl>

최상위 Tag로 <tran>과 <cyl>두개가 있는 형태지만 이러한 형식은 허용하지 않습니다.(단, 하위 Tag는 몇개가 있어도 상관없습니다.)

(3) XML도 HTML과 마찬가지로 시작Tag와 마침Tag가 존재하며 둘은 같이 써야 합니다.

<car>똥차</car>

단 중간에 내용이 없는 Tag일 경우 <car/>형식으로 표현이 가능합니다.(이때 각 Tag는 영문자이외에 숫자로 시작해서는 안되며 <c ar>처럼 공백을 포함할 수는 없습니다.)

(4) XML도 HTML과 같이 각 Tag에 속성을 부과할 수 있습니다.

<?xml version="1.0" encoding="euc-kr"?>
<tran>
 <car age="old">똥차</car>
 <air>보잉747</air>
</tran>

car Tag에 age라는 속성이 부과되었으며 속성값으로 old라는 값을 지정하였습니다.

(5) 각 Tag는 대문자와 소문자를 구분합니다.

<car></car><Car></Car><CAR></CAR>

<car>와 <Car>, <CAR> Tag는 모두 관련이 없는 완전 별개의 Tag입니다.

(6) HTML에서 쓰던 특수문자(&nbsp;, &amp;등등)표현식은 그대로 사용할 수 있습니다.

<?xml version="1.0" encoding="euc-kr"?>
<tran>
 <car age="old">똥차&amp;</car>
 <air>보잉747</air>
</tran>


XML문서를 Web Brawser를 통해 확인합니다.

(7) 주석은

2. XML의 Namespace

위에서 XML작성시 <car> Tag는 자동차를 의미하는 것으로 사용한다고 가정해 보겠습니다. 이때 다른 사람도 자신의 XML문서를 작성하면서 Card라는 것을 의미하는 <car> Tag를 정의할 수 있을 것입니다. 즉, 같은 Tag를 전혀 다른 사람이 전혀 다른 의미와 용도로 사용할 수 있는 가능성이 존재하는 것입니다.

이런 중복되는 상황을 피하기 위해 XML Tag를 정의한 사람이 누구인지에 대한 이름표를 붙일 수 있는 기능이 있습니다. 그것이 바로 Namespace입니다. (참고로 .net Programming에서도 Namespace라는 것이 있는데 둘다 거의 비슷한 의미를 갖고 있습니다.)

Namespace는 해당 Tag의 xmlns속성을 통해 정의하며 대부분 XML문서의 가장 처음부분에 위치하도록 합니다.

<car xmlns="이름">똥차</car>

이때 "이름"이라는 속성값 마저도 중복되는 내용으로 쓸 가능성이 존재할 것입니다. 예를 들어 "이름"을

xmlns="홍길동"

으로 했다면 동명이인인 사람이 역시 같은 이름인 "홍길동"을 사용할 수 있기에 "이름"에 해당하는 내용은 중복되지 않을 만한 값으로 기술해야 합니다.(주민등록번호나 Internet 주소등)

<car xmlns="http://cliel.com/">똥차</car>

3. DTD(Document Type Definition)

특정 회사의 각 부서명과 해당 부서에서 근무하는 사원수를 정의한 XML문서를 작성한다고 가정해 보겠습니다.

<?xml version="1.0" encoding="euc-kr"?>
<compy>
 <dept>
  <name>관리부</name>
  <cont>3</cont>
 </dept>
 <dept>
  <name>경리부</name>
  <cont>2</cont>
 </dept>
 <dept>
  <name>기술부</name>
  <cont>5</cont>
 </dept>
</compy>

<compy>를 기준으로 <dept>에 의해 각 부서를 나누고 해당 부서의 이름과 사원수를 기록합니다.

그런데 이 문서가 한 사람이 아닌 여러사람에 의해 관리된다면 <name>을 <names>라고 한다던가 아니면 <dept>하위에 <customer>이라는 엉뚱한 Tag를 집어넣등의 관리적 오류가 발생할 가능성이 있습니다.

이때 XML문서에서는 DTD라는 것을 설정하여 위와 같은 문제를 피할 수 있습니다. DTD는 XML문서를 구성하고 있는 각 Tag를 명확히 정의함으로써 틀린 구문이 작성되면 이를 허용하지 않도록 하기 위한 것입니다.

XML에서 DTD는 다음과 같이 XML문서가 시작되기 전에 먼저 기술하여 각 Tag가 어떻게 쓰여야 하는지 나타내도록 합니다.

<?xml version="1.0" encoding="euc-kr"?>
<!DOCTYPE rule [
 <!ELEMENT compy (dept+)>
 <!ELEMENT dept (name, cont)>
 <!ELEMENT name (#PCDATA)>
 <!ELEMENT cont (#PCDATA)>
]>
<compy>
 <dept>
  <name>관리부</name>
  <cont>3</cont>
 </dept>
 <dept>
  <name>경리부</name>
  <cont>2</cont>
 </dept>
 <dept>
  <name>기술부</name>
  <cont>5</cont>
 </dept>
</compy>

rule라는 이름으로 이 XML문서의 형식을 정의하였습니다. 이 형식에 의하면 compy는 dept라는 하위 Tag로 구성되며(compy (dept*)) dept Tag는 다시 name과 conf Tag로 구성됨을(dept (name, cont))정의하고 있습니다.


물론 DTD가 정의 되었다고 해서 위 규칙에 벗어나는 형식으로 XML작성하면 오류가 발생하거나 쓰기 자체를 금지하지는 않습니다. 다만 이 XML문서가 어떤 형식으로 이루어져 있는지를 알려줌으로 인해 상호간 XML형식을 맞출 수 있도록 약속을 하는 것이죠.

3. XML InfoSet

InfoSet은 일종의 개념이다. XML문서를 이루는 요소에서 중요한게 무엇인가를 의미하는 것인데 XML문서가 이 개념만 맞추고 있으면 모두 정상적인 XML문서로 가정합니다.

예를 들어

<?xml version="1.0" encoding="euc-kr"?>
<compy>
 <dept>
  <name>관리부</name>
  <cont>3</cont>
 </dept>
 <dept>
  <name>경리부</name>
  <cont>2</cont>
 </dept>
 <dept>
  <name>기술부</name>
  <cont>5</cont>
 </dept>
</compy>

이러한 XML을

<?xml version="1.0" encoding="euc-kr"?><compy><dept><name>관리부</name><cont>3</cont></dept>
 <dept><name>경리부</name><cont>2</cont></dept><dept><name>기술부</name><cont>5</cont></dept></compy>

위와 같은 형태로 바꿔도 무방합니다. 공백은 XML을 이루는데 중요한 요소가 아니며 형식에 위배되지도 않는 것입니다.

'Programming' 카테고리의 다른 글

정규표현식  (0) 2012.05.18
ANSI 문자 코드표  (0) 2011.02.25
XML을 써보자  (0) 2010.12.31
변수명및 메소드(Method)등 명명 규칙  (0) 2010.12.21
0 0
Programming/Microsoft SQL Server
XML 참고 : [Computer, IT] - XML을 써보자

SQL Server에서 특정 Data를 조회하기 위해 Query를 날리면 보통의 경우 Table형태로 그 결과를 출력하게 됩니다.

Select *
From HumanResources.Department;


하지만 필요한 경우 결과를 XML형태로도 조회할 수 있습니다. 구현 방법도 아주 간단한데 단지 Query 뒤에 for xml option을 추가하고 원하는 형식에 따라 raw, auto, explicit을 덧붙이기만 하면 됩니다.

1. Raw

Raw은 Xml형태로 결과를 출력할때 Table에 해당하는 각 Column을 요소의 속성으로 한뒤 Table의 실제 Data를 속성의 값으로 표현하도록 합니다.

Select DepartmentID, Name, GroupName, ModifiedDate
From HumanResources.Department
For Xml Raw;


이때 각 행 요소의 이름은 row로 표시됩니다. 만일 이 이름이 마음에 들지 않는다면 괄호(())안에 원하는 이름을 지정해 줄 수 있습니다.

Select Top(3) DepartmentID, Name, GroupName, ModifiedDate
From HumanResources.Department
For Xml Raw('mytag');

요소 이름을 row가 아닌 mytag로 출력되도록 지정하였습니다.


Raw에 Elements요소를 추가하면 위에서처럼 단일 행으로 출력되는 형태가 아니라 각 행별(<row>)로 Column을 XML 요소로 하고 Table의 내용을 요소의 값으로 표현하도록 합니다.

Select Top(3) DepartmentID, Name, GroupName, ModifiedDate
From HumanResources.Department
For Xml Raw, Elements;


위 결과에서 Table의 Data를 요소의 값으로 표시하였으며 더불어 각 행마다 계층적으로 Query결과가 표현되었음을 확인할 수 있습니다. 이때 이 계층 구조의 요소에 최상위 요소를 추가하고자 하신다면 Root를 구문을 사용하십시오.

Select Top(3) DepartmentID, Name, GroupName, ModifiedDate
From HumanResources.Department
For Xml Raw, Elements, Root('topelement');

Root option으로 'ttopelement'라는 최상위 요소가 추가되도록 하였습니다.


참고:
이전까지의 내용도 그렇고 이후에 설명될 내용에서도 마찬가지지만 각 Option을 어떻게 사용할지는 개발자가 비교적 자유롭게 정할 수 있는 대목입니다. 예제에서도 Root는 마치 Elements option이 쓰여졌을때만 사용한다라는 오해의 소지를 갖게 될 수 있으나 실제로는 그렇지 않고 단독으로 쓸 수 있습니다.(물론 다른 Option도 특별한 경우를 제외하고는 모두 마찬가지 입니다.)

XML문서를 이루는 요소중의 하나로 DTD라는 것이 있습니다. 이 DTD를 통해 해당 XML문서의 구조를 알 수 있도록 하는데 Query에서 XmlData를 쓰면 그 결과로 XML이 표시될때 해당 XML이 어떻게 구성되어 있는지에 대한 DTD를 같이 나타내도록 할 수 있습니다.

Select Top(3) DepartmentID, Name, GroupName, ModifiedDate
From HumanResources.Department
For Xml Raw, XmlData;


XML출력결과의 상단에 Schema라는 이름으로 해당 XML구조를 나타내고 있습니다.

일반적인 Data형 Table의 경우에는 대부분 XML형태로 결과를 얻는데 큰문제가 없습니다. 그러나 Column의 Datatype형태가 Image나 Text와 같은경우에는 이 Data자체를 XML로 표현하기가 곤란할 수 있습니다. 따라서 해당 Column의 내용을 Binary로 변화시켜서 표현해야 하는데 이때 Binary Base64구문을 사용하시면 됩니다.

Select Top(2) ProductPhotoID, ThumbNailPhoto, ThumbnailPhotoFileName
From Production.ProductPhoto
For Xml Raw, Binary Base64;

AdventureWorks2008 예제 Database의 Production.ProductPhoto Table에는 ThumbNailPhoto라는 Image Datatype의 사진(그림)정보가 저장된 Column이 있습니다.

(실제 Binary Base64 출력결과를 보면 이보다 훨씬 길게 나타납니다.)

일반적인 방법으로 XML형태의 표현이 불가능한 경우는 또 있습니다. 바로 Table에 Null이 있는 경우 입니다.

Select Top(3) AddressID, AddressLine1, AddressLine2
From Person.Address
For Xml Raw;

Person.Address Table의 AddressID와 AddressLine1, AddressLine2를 3행까지 XML 형태로 출력하도록 합니다.


결과를 놓고 보니 뭔가 좀 이상하다는 생각할 할 수 있습니다. 분명 Query에서는 AddressLine2까지 표시하라고 했지만 AddressLine1만 나왔기 때문입니다. 이는 XML출력시에 Null은 결과에서 아예 제외하기 때문입니다. 이러한 현상을 막으려면 Xsinil Option을 써야합니다.

Select Top(3) AddressID, AddressLine1, AddressLine2
From Person.Address
For Xml Raw, Elements Xsinil;

Xsinil이 Elements와 함께 구현되었습니다.


결과에서는 Null에 해당하는 부분의 속성이 xsi:nil="true" 형태로 나타나 이 요소에 대한 Column의 내용이 null이라는 것을 알려주고 있습니다.

2. Auto

Raw사용시 이름을 지정해 주지 않으면 XML의 각 요소를 row항목으로 표시했었는데 Auto는 row가 아닌 조회되는 해당 Table명으로 XML의 요소를 이루도록 합니다.

Select Top(3) DepartmentID, Name, GroupName, ModifiedDate
From HumanResources.Department
For Xml Auto;


row대신 해당 Table명으로 각 요소를 이루고 있습니다.

어떻게 보면 Raw에서 Table영으로 이름을 지정해 준것과 결과가 동일하다고 볼 수 있겠습니다. 아무래도 의미없는 row대신 Table명으로 요소를 자동표시한다고 해여 이름이 auto인듯 합니다.^^;;

참고:
Table이름에 As구문을 사용하여 다른 이름을 부여했다면 해당 이름으로 요소명이 지정됩니다.

3. Explicit

Explicit는 Raw나 Auto와는 달리 출력되는 XML의 각 요소를 비교적 자유롭게 작성할 수 있도록 해줍니다. Result set을 원하는 XML형태로 조회하는 것이 가능하다는 얘기인데 기능이 우수한 만큼 사용하기도 다소 번거롭습니다.

일단 간단하게나마 짚어보도록 하겠습니다.

Select 1 As Tag, Null As Parent, DepartmentID As [Department!1!ID]
From HumanResources.Department
Order By [Department!1!ID]
For XML Explicit;

HumanResources.Department Table의 DepartmentID Column을 Explicit style로 출력합니다.

Select에서 1 As Tag는 출력할 Tag요소가 하나(1)인것만을 지정한다는 의미로 해석하시면 됩니다. 또한 출력하려는 요소의 부모요소는 현재 존재하지 않으므로 Null As Parent로 부모 요소를 지정합니다.(나중에 설명 드리겠지만 요소를 늘리려면 조회하는 구문을 하나 더 써서 Union으로 Join해야 합니다.)

[Department!1!ID]에서 Department는 Department요소를 추가시킨다는 의미 입니다. 뒤이은 !은 요소와 요소의 차수 그리고 속성을 구분해 주는 구분자 역활을 합니다.

차수는 현재 1단계 level의 요소만을 출력할 것이므로(Select 에서 1 As Tag로 하여 출력할 Tag요소가 하나라는 것을 이미 정의하였습니다.)1이라고 쓰고 다시 구분자(!)를 둔뒤 속성명으로 ID를 부여하여 Department요소에 ID라는 속성을 추가시켜 해당 속성값으로 DepartmentID Column내용을 출력하도록 합니다.


이번에는 위 결과에 하위 요소를 하나더 추가시켜 보겠습니다. Explicit option으로 요소를 추가하려면 해당 조회구문을 더 만들고 Union으로 Join하는 형태로 나가야 합니다.

Select Top(3) 1 As Tag, Null As Parent, DepartmentID As [Department!1!ID], Null As [Names!2!Nm]
From HumanResources.Department
Union
Select Top(3) 2 As Tag, 1 As Parent, DepartmentID, Name
From HumanResources.Department
Order By [Department!1!ID], [Names!2!Nm]
For XML Explicit;

DepartmentID Column에 이어 Name Column을 Department 요소의 하위요소로 추가하여 조회 하도록 하였습니다. 이처럼 요소를 늘리려면 그 만큼 Union Join을 통해 각 요소의 추가적인 조회 구분을 더 만들어야 합니다.

두번째 Select문에서는 2 As Tag라고 하였습니다. 말 그대로 해당 Select문에서는 DepartmentID와 Name두개의 Column을 조회하여 각 Tag 요소로 출력하기 때문입니다.

또한 1 As Parent라고 한것은 Name조회한 요소를 Department요소의 하위 요소로 출력할 경우 부모 요소는 Department요소가 되기 때문에 Parent를 1이라고 정의한 것입니다. 반면 첫번째 Select문에서는 여전히 조회하는 Column이 하나이므로 출력할 Tag요소도 하나이기 때문에 1 As tag는 변하지 않으며 DepartmentID에 대한 요소의 부모 요소도  첫번째 Select문에 존재하지 않으므로 부모 요소는 Null을 유지하고 있습니다.

한편 첫번째 Select문에 DepartmentID이후 Null을 조회하도록 한 것은 해당 요소의 내용은 두번재 Select문에서 가져오기 때문입니다. 결국 두번째 Select문에서 가져온 Name column값을 Names라는 요소로 만들고 하위 2번째 요소로 정한다음 Nm속성을 만들어 속성의 값으로 표시([Names!2!Nm])한 것입니다.

두번째 Select문에서 DepartmentID와 Name은 이미 첫번째 Select문에서 각 Column에 대한 요소를 [Names!2!Nm]처럼 정의했기 때문에 또 다시 정의하는 것은 불필요합니다. 왜냐하면 Column의 이름만 써주면 그걸로 충분하기 때문이죠.

Top(3)은 출력되는 부분이 너무 커서 행을 다소 줄이기 위해 추가한 것입니다. 그리고 Order By는 조회할 각 Column을 정렬해 주지 않으면 XML출력시 결과요소가 서로 뒤엉키는 문제가 생기지 않도록 정렬하기 위한 것입니다.


이번에는 Department요소와 Names요소에 이어 Group요소를 하나더 추가해 보겠습니다.

요소를 늘리기 위해 조회 구문을 하나 더 만들어 Union으로 join합니다. 세번째 Select문의 구현 원리도 두번째 설명드린 구현원리와 같습니다.


물론 부모 요소는 반드시 첫번째 Select문의 1이어야할 필요는 없습니다. 필요하다면 바꿀 수 있는데 이런경우 당연히 출력되는 형태도 달라질 것입니다.

Select Top(3) 1 As Tag, Null As Parent, DepartmentID As [Department!1!ID], Null As [Names!2!Nm], Null As [Group!3!Name]
From HumanResources.Department
Union
Select Top(3) 2 As Tag, 1 As Parent, DepartmentID, Name, Null
From HumanResources.Department
Union
Select Top(3) 3 As Tag, 2 As Parent, DepartmentID, Name, GroupName
From HumanResources.Department
Order By [Department!1!ID], [Names!2!Nm], [Group!3!Name]
For XML Explicit;

세번째 Select문에서 부모 요소를 1이 아닌 2라고 지정하였습니다. 즉, 두번째 요소인 Names요소를 부모요소로 지정한 것입니다.


이번에는 좀 다르게 요소를 추가하지 않고 Names 요소에다가 Name과 GroupName Column의 내용을 Nm, Group의 두개 속성으로 만들어 표현해 보도록 하겠습니다.

Select Top(3) 1 As Tag, Null As Parent, DepartmentID As [Department!1!ID], Null As [Names!2!Nm], Null As [Names!2!Group]
From HumanResources.Department
Union
Select Top(3) 2 As Tag,  1 As Parent,  DepartmentID,  Name,  GroupName
From HumanResources.Department
Order By [Department!1!ID], [Names!2!Nm], [Names!2!Group]
For XML Explicit;

이전보다 Select문이 하나 더 줄었습니다. 기존에는 Department와 Names 그리고 Group 이렇게 3개의 요소를 출력하려 했으므로 세개의 Select문을 Union Join해야 했지만 이번에는 기존 Group요소를 없애고 대신 해당 Group내용을 Name요소에 통합하여 두개의 속성으로 만들고 출력하기 때문에(출력할 요소가 Department와 Name두개 이기 때문에) Join될 Select구문도 두개면 충분한 것입니다.

먼저 첫번째 Select문에서 두번째 조회 column부분에 [Name!2!Nm]이라고 정의하면 Name요소가 만들어질 것이고 그 이후에 만들어진 Name요소에다가 속성만을 추가할 것이므로 세번째는 요소명과 출력될 요소의 차수를 똑같이 써서 추가할 속성명만 [Names!2!Group]처럼 지정해 주면 됩니다.

물론 두번째 Select문에서는 Group속성에 표시할 Column(예제에서는 GroupName)을 지정해 줘야 하겠지요.


Names요소에 Nm과 Group속성 두개가 추가되고 각각의 속성에 Name과 GroupName내용을 표시하고 있습니다.

이제까지 예제에서는 모두 속성을 통해 값을 표시하고 있지만 이렇게 하지 않고 요소 자체에다가 해당 내용이 보여지도록 지정할 수도 있습니다.

Select Top(3) 1 As Tag, Null As Parent, DepartmentID As [Department!1!ID], Null As [Names!2!Nm!Element], Null As [Names!2!Group!Element]
From HumanResources.Department
Union
Select Top(3) 2 As Tag, 1 As Parent, DepartmentID, Name, GroupName
From HumanResources.Department
Order By [Department!1!ID], [Names!2!Nm!ELEMENT], [Names!2!Group!ELEMENT]
For XML Explicit;

요소 지시자에 !로 구분하여 Element를 추가하였습니다. 첫번째 Select문에서 두번재와 세번째 Column조회 부분을 주목해 주십시오.


각 Column의 값이 속성이 아닌 Tag 요소를 통해 표시됨을 확인할 수 있습니다.

참고:
출력하려는 XML의 각 요소에 ID를 지정하고자 하신다면 Element를 지정한 것과 같이 ID를 지정하시면 됩니다. 또한 조회하는 Column에 Null이 있다면 Element대신 Elementxsinil을 사용하시면 Null이 있는 Column도 조회가 가능합니다.
0 0
Programming/Microsoft SQL Server
For Xml은 기존 Table형태의 결과를 XML형태로 바꿔서 조회하는 기능을 제공합니다. 반면 OpenXml은 For Xml과 반대로 XML형태의 Data를 Table형태로 바꿔서 조회하는 기능을 가지고 있습니다.

우선 AdventureWorks2008예제 Database의 HumanResources.Department Table을 XML형태로 조회하여 간단한 XML Data를 생성하도록 하겠습니다.

Select Top(3) 1 As Tag,
 Null As Parent,
 DepartmentID As [Department!1!ID],
 Null As [Names!2!Nm],
 Null As [Group!3!Name!Element]
From HumanResources.Department
Union
Select Top(3) 2 As Tag,
 1 As Parent,
 DepartmentID,
 Name,
 Null
From HumanResources.Department
Union
Select Top(3) 3 As Tag,
 2 As Parent,
 DepartmentID,
 Name,
 GroupName
From HumanResources.Department
Order By [Department!1!ID], [Names!2!Nm], [Group!3!Name!Element]
For XML Explicit;


위에서 만들어진 XML Data를 XML 변수에 저장합니다.

Declare @MyXml Xml;
Set @MyXml = '
<TopEle>
<Department ID="1">
  <Names Nm="Engineering">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="2">
  <Names Nm="Tool Design">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="3">
  <Names Nm="Sales">
    <Group>
      <Name>Sales and Marketing</Name>
    </Group>
  </Names>
</Department>
</TopEle>';

XML형 Data변수에 XML내용을 저장합니다.(최상위 요소인 <TopEle>는 원래 XML에서 최상위 요소가 존재해야 한다는 제약으로 인해 새로 추가시킨 최상위 요소입니다.)

이제 다음 순서로 XML 문서의 구문분석 기능을 갖고 있는  sp_xml_preparedocment System Procedure를 사용하여 해당 XML을 분석하도록 해야 합니다. sp_xml_preparedocument Procedure는 인수로 전달된 XML Data에 대한 handle값을 정수형태로 반환하므로 이후 부터 XML문서를 조작할때는 이 Handle값을 이용하게 됩니다.

Declare @MyXml Xml;
Set @MyXml = '
<TopEle>
<Department ID="1">
  <Names Nm="Engineering">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="2">
  <Names Nm="Tool Design">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="3">
  <Names Nm="Sales">
    <Group>
      <Name>Sales and Marketing</Name>
    </Group>
  </Names>
</Department>
</TopEle>';

Declare @iHandle Int;
Exec sp_xml_preparedocument @iHandle Output, @MyXml;


sp_xml_preparedocument Procedure를 통해 @iHandle에 해당 handle값을 저장합니다.

여기까지 OpenXml을 사용할 준비가 완료된 것입니다. OpenXml사용시에는 다음과 같이 위에서 얻어진 Handle값을 인수로 주고 출력할 기준이 되는 요소를 지정해서 사용면 됩니다.

Declare @MyXml Xml;
Set @MyXml = '
<TopEle>
<Department ID="1">
  <Names Nm="Engineering">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="2">
  <Names Nm="Tool Design">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="3">
  <Names Nm="Sales">
    <Group>
      <Name>Sales and Marketing</Name>
    </Group>
  </Names>
</Department>
</TopEle>';

Declare @iHandle Int;
Exec sp_xml_preparedocument @iHandle Output, @MyXml;

Select *
From OpenXml(@iHandle, '/TopEle/Department')
Order By id;


OpenXml을 통하여 sp_xml_preparedocument에서 구분분석된 XML Data를 TopEle의 Department요소를 중심으로 출력하도록 합니다.


위 Query결과를 보면 XML Data에 대한 내용이 아니라 sp_xml_preparedocument를 통해 구문분석된 결과를 보여고 있다는 것을 알 수 있습니다.

이 결과 Table에서 가장 첫번째 id는 XML을 분석한 요소, 속성, 값등 XML을 이루고 있는 구조 하나하나를 모두 나열하고 거기에 번호를 붙여 id로 표시한 겁니다.

두번째 parentid는 해당 id의 요소가 어떤 요소에 속해 있는지를 나타내는 것입니다. 우선 첫번째 행과 두번째 행만을 살펴보자면 id가 2번인 요소는 Department요소로서 부모 요소는 TopEle가 되며 이 최상위 요소는 id가 0이므로 parentid가 0으로 표시되고 있습니다. 또한 id가 3인 요소는 ID요소로 이 ID요소는 id가 2번인 Department에 속해 있는 속성이기 때문에 parentid값으로 2가 나타나고 있습니다.

세번째 nodetype는 해당 요소가 어떤 type인지를 나타내고 있는 것으로 이 값이 1이면 XML의 요소, 2이면 속성, 3이면 속성의 값을 의미합니다.

네번째 localname은 요소의 이름이고 여덟번째 prev는 요소가 단순한 하위요소가 아니라 새로 시작되는 Group요소일 경우 이전에 먼저 시작된 상위 Group의 id를 의미합니다.

아홉번째 text는 nodetype이 3(속성)일 경우 해당 속성의 값을 표시하는 부분입니다.

위 결과를 가지고 이제 OpenXml에 With option을 추가하여 원래 의도한 결과를 다시 조회해 보겠습니다.

Declare @MyXml Xml;
Set @MyXml = '
<TopEle>
<Department ID="1">
  <Names Nm="Engineering">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="2">
  <Names Nm="Tool Design">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="3">
  <Names Nm="Sales">
    <Group>
      <Name>Sales and Marketing</Name>
    </Group>
  </Names>
</Department>
</TopEle>';

Declare @iHandle Int;
Exec sp_xml_preparedocument @iHandle Output, @MyXml;

Select *
From OpenXml(@iHandle, '/TopEle/Department', 1)
With (ID Int);

Select *
From OpenXml(@iHandle, '/TopEle/Department/Names', 1)
With (Nm Char(15));


두번째와 세번째 Select문을 주목해 주십시오. 첫번째 OpenXml에는 /TopEle/Department 가 지정되어 Department요소를 중심으로 하겠다고 하는 것이며 뒤에 1은 속성을 조회한다는 의미합니다. With을 통해 ID Int라고 지정했으므로 결국 Department요소에서 ID속성의 값을 Int형으로 가져오라는 뜻이 됩니다.

두번째 Select문도 마찬가지 인데 /TopEle/Department/Names 로 지정되어 해당 요소의 Nm속성을 Char형으로 가져오게 합니다.


물로 위 두개의 Select문을 합쳐 다음과 같이 하나로 표시할 수도 있습니다.

Declare @MyXml Xml;
Set @MyXml = '
<TopEle>
<Department ID="1">
  <Names Nm="Engineering">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="2">
  <Names Nm="Tool Design">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="3">
  <Names Nm="Sales">
    <Group>
      <Name>Sales and Marketing</Name>
    </Group>
  </Names>
</Department>
</TopEle>';

Declare @iHandle Int;
Exec sp_xml_preparedocument @iHandle Output, @MyXml;

Select *
From OpenXml(@iHandle, '/TopEle/Department/Names', 1)
With (ID Int
'../@ID', Nm Char(15));


With option을 보시면 ID int뒤에 '../@ID'라는 내용이 추가된걸 알 수 있습니다. 이것이 의미하는 것은 '상위요소(../)에서 ID속성(@ID)의 값을 가져온다.'는 뜻을 담고있습니다.

이렇게 하는 이유는 OpenXml에 요소지정시 /TopEle/Department/Names 라고 하였으므로 결국Names 요소 이하의 내용만 가져오게 되는데 이렇게 되면 Department요소의 ID속성값은 가져오지 못하는 문제가 생기게 되므로 '../@ID'를 통해 상위 요소의 속성값을 가져올 수 있도록 지정해야 하는 것입니다.

그리고 OpenXml로 조회시 가져올 항목이 늘어나면 With에 Column지정할때 콤마(,)를 사용하여 각 Column을 구분해 주시면 됩니다.


이번에는 Department ID속성의 내용과 더불어 Name요소의 Data값을 가져와 보도록 하겠습니다.

Declare @MyXml Xml;
Set @MyXml = '
<TopEle>
<Department ID="1">
  <Names Nm="Engineering">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="2">
  <Names Nm="Tool Design">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="3">
  <Names Nm="Sales">
    <Group>
      <Name>Sales and Marketing</Name>
    </Group>
  </Names>
</Department>
</TopEle>';

Declare @iHandle Int;
Exec sp_xml_preparedocument @iHandle Output, @MyXml;

Select *
From OpenXml(@iHandle, '/TopEle/Department/Names/Group', 2)
With (ID Int
'../../@ID', Name Char(50));


Name의 Data값을 가져오기 위해 요소를 /TopEle/Department/Names/Group까지 지정하였습니다. 또한 속성의 값이 아닌 요소의 값을 가져오게 되므로 1에서 2로 바꿔 요소의 값을 가져오도록 하였습니다.

이때 ID는 기존에 /TopEle/Department/Names에서 /TopEle/Department/Names/Group이라고 한단계 더 내려간 요소를 지정하였으므로 ID int뒤에도 ../ 의 경로지정을 하나 더 붙여 상위 2개 요소위(../../)에서 ID속성의 값을 가져와야 한다고 지정하였습니다.

여기까지 보면 'OpenXml에서 2로 하여 요소의 값을 가져오도록 지정했는데 ID는 속성값이므로 문제가 되지 않을까?' 라고 의문을 가질 수 있지만 크게 문제되지는 않습니다. ID앞에 @문자를 붙여 '가져올 내용은 속성의 값이다.'라고 명시하였기 때문입니다.


참고 :
요소의 값과 속성을 모두 포함시키려면 다음처럼 3(요소1 + 속성2)을 지정해야 합니다.

From OpenXml(@iHandle, '/TopEle/Department/Names/Group', 3)

위에서 언급된 내용을 토대로 해당 XML의 모든 내용을 가져와 보도록 하보겠습니다.

Declare @MyXml Xml;
Set @MyXml = '
<TopEle>
<Department ID="1">
  <Names Nm="Engineering">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="2">
  <Names Nm="Tool Design">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="3">
  <Names Nm="Sales">
    <Group>
      <Name>Sales and Marketing</Name>
    </Group>
  </Names>
</Department>
</TopEle>';

Declare @iHandle Int;
Exec sp_xml_preparedocument @iHandle Output, @MyXml;

Select *
From OpenXml(@iHandle, '/TopEle/Department/Names/Group', 2)
With (ID Int
'../../@ID', Nm Char(15) '../@Nm', Name Char(50));

Select Top(3) DepartmentID, Name, GroupName
From HumanResources.Department;



위 결과를 실제 Table의 내용과 비교해 보시기 바랍니다.

OpenXml을 사용할때 Select문을 보시면 일반 Table 조회와 별 차이가 없습니다. 따라서 일반 Table처럼 where문으로 특정한 조건의 내용만 가져올 수 있고 Max나 Sum처럼 수식을 정할 수도 있습니다.

Declare @MyXml Xml;
Set @MyXml = '
<TopEle>
<Department ID="1">
  <Names Nm="Engineering">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="2">
  <Names Nm="Tool Design">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="3">
  <Names Nm="Sales">
    <Group>
      <Name>Sales and Marketing</Name>
    </Group>
  </Names>
</Department>
</TopEle>';

Declare @iHandle Int;
Exec sp_xml_preparedocument @iHandle Output, @MyXml;

Select max(ID)
From OpenXml(@iHandle, '/TopEle/Department/Names/Group', 2)
With (ID Int
'../../@ID', Nm Char(15) '../@Nm', Name Char(50));

Select *
From OpenXml(@iHandle, '/TopEle/Department/Names/Group', 2)
With (ID Int
'../../@ID', Nm Char(15) '../@Nm', Name Char(50))
Where ID = 3;


첫번째 Selet에서는 ID가 가장 큰 값을 가져오도록 했으며 두번째 Select에서는 ID가 3인 내용만 조회되도록 하였습니다.


OpenXml을 사용하기 위해서는 XML을 분석할 sp_xml_preparedocument Procedure를 호출한다고 하였습니다.

이 호출된 sp_xml_preparedocument Procedure는 해당 XML Data를 Memory에 올려놓고 구문분석과 handle을 반환하는 역활을 수행합니다. 이때 Memory에 Load된 XML을 제거해 주지 않으면 계속해서 Memory를 잡아먹는 낭비를 가져올 수 있습니다.

따라서 해당 XML에 대해 적절한 처리를 수행하고 나면 다음 처럼 sp_removedocument Procedure를 사용하여 Memory에서 XML Data를 제거해야할 필요가 있습니다.

Declare @MyXml Xml;
Set @MyXml = '
<TopEle>
<Department ID="1">
  <Names Nm="Engineering">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="2">
  <Names Nm="Tool Design">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="3">
  <Names Nm="Sales">
    <Group>
      <Name>Sales and Marketing</Name>
    </Group>
  </Names>
</Department>
</TopEle>';

Declare @iHandle Int;
Exec sp_xml_preparedocument @iHandle Output, @MyXml;

Select *
From OpenXml(@iHandle, '/TopEle/Department/Names/Group', 2)
With (ID Int
'../../@ID', Nm Char(15) '../@Nm', Name Char(50));

Exec sp_xml_removedocument @iHandle;


sp_xml_removedocument Procedure에 XML의 handle을 넘겨 Memory에서 제거되도록 합니다.
0 0
Programming/Microsoft SQL Server
XQuery는 XML을 조회한다는 개념에서 한발 더 나아가 직접 XML Data에 접근할 수 있도록 해줍니다. 이때 어떠한 방식으로 접근하느냐에 따라 3가지 형식으로 나뉩니다.

우선 XQuery를 사용하기 전에 먼저 Sample XML Data를 만든 후 이 XML Data를 대상으로 XQuery를 적용시켜 보도록 하겠습니다.

Declare @MyXml Xml;
Set @MyXml = '
<TopEle>
<Department ID="1">
  <Names Nm="Engineering">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="2">
  <Names Nm="Tool Design">
    <Group>
      <Name>Research and Development</Name>
    </Group>
  </Names>
</Department>
<Department ID="3">
  <Names Nm="Sales">
    <Group>
      <Name>Sales and Marketing</Name>
    </Group>
  </Names>
</Department>
</TopEle>';

1. query

XML Data의 요소를 얻어오는데 사용되는 method입니다.

Select @MyXml.query('/TopEle[1]/Department[2]');

Data형식이 XML이면 그것이 변수든 Column이든 상관없이 XQuery를 적용시킬 수 있습니다. 위에서는 @MyXml 변수에 XQuery의 query를 적용시켜 원하는 요소를 가져오도록 하였습니다.

먼저 /TopEle[1]을 통해 첫번째 TopEle요소의 하위 Department요소중 두번째 요소(/Department[2])내용을 가져오도록 합니다. 보시는 바와 같이 각 요소는 '/'문자로 구분하며 요소의 순서는 []안에 지정합니다.


이번에는 변수를 사용하여 XML문서내에 있는 각 Name의 요소값을 가져와 보겠습니다.

Select @MyXml.query('for $s in /TopEle/Department/Names/Group/Name return data($s)');

query내에 있는 for는 반복을 의미합니다. 즉, XML의  /Top /TopEle/Department/Names/Group/Name요소를 반복적으로 모두 확인하여 변수 $s에 넣고(data($s)) 그 결과를 출력하도록 하는 것입니다.

주의 :
XQuery사용시 대/소문자를 명확히 구분합니다. 예를 들어 for를 For라고 하면 오류가 발생합니다.


이번에는 요소의 값이 아니라 속성의 값을 가져와 보도록 하겠습니다.

Select @MyXml.query('for $s in /TopEle/Department/@ID return data($s)');
Select @MyXml.query('for $s in /TopEle/Department/Names/@Nm return data($s)');

첫번째 XQuery에서는 /TopEle/Department의 ID속성값을 가져오도록 하였고 두번째 XQuery에서는 /TopEle/Department/Names요소의 Nm속성값을 가져오도록 하였습니다.

여기서 '/'는 요소를, '@'는 속성을 의미합니다.


또한 XQuery는 XML Data에서 다음처럼 조건에 맞는 내용만 가져올 수도 있습니다.

Select @MyXml.query('for $s in /TopEle/Department[@ID eq "2"] return $s');

/TopEle/Department요소의 ID속성을 찾아서 값이 2인것만([@ID eq "2"]) 가져오도록 합니다. (XQuery조건문으로 일치하는 값을 지정할 수 있도록 합니다.)

참고 :
Data($s)를 통해서 값을 가져오는 경우는 해당 변수에 특정 값이 존재할때만 가능합니다. 위에서 제시된 예제는 특정 값이 아니라 XML Data자체이므로 data()를 쓰지 않습니다.


다음은 다른 XML구문을 추가하여 조회하는 예제입니다.

Select @MyXml.query('for $s in /TopEle/Department return <myXml><NewValue>{data($s/@ID)}</NewValue><NewString>{data($s/Names/@Nm)}</NewString></myXml>');

XQuery결과에 상위 <myXml>요소를 추가하고 각 값마다 <NewValue>요소와 <NewString>요소를 추가하여 XML형태로 결과값을 반환하도록 하고 있으며 동시에 두가지 값을 가져오는 방법도 제시하고 있습니다.

이때 주목해야할 부분이 있는데 두번째 data($s/Names/@Nm)부분을 보시면 for에서 in다음에 /TopEle/Department요소를 지정하여 궁극적으로는 Nmes요소의 Nm속성값을 가져올 수 없을지도 모르지만 이렇게 값을 반환하는 부분에서 하위 요소와 속성을 지정하면(/Names/@Nm) 해당 요소와 속성의 값을 가져올 수 있게 됩니다.


2. value

query는 XML data내에서 각 요소자체를 주출하는 역활을 하지만  value는 요소가 아닌 값만을 가져올 수 있도록 합니다.

Select @MyXml.value('(/TopEle/Department[3])[1]', 'Char(50)');

TopEle전체요소중에서 Department세번째 요소에 있는 첫번째 값을 Char(50) Data형으로 가져옵니다.


value를 사용하면 단순히 값을 가져오는것 이외에 실제 값이 있는가 없는가를 판단할 수도 있습니다.

Select @MyXml.value('some $s in /TopEle/Department/Names satisfies $s/@Nm="Sales"', 'Char(50)');

some을 통해 /TopEle/Department/Names요소의 Nm속성값에 "Sales"가 있으면 true 없으면 false를 반환합니다. (비교자는 satisfies를 사용합니다.)


값을 비교하여 있는지 없는지 판단하는 것은 some이외에 every도 있습니다. some은 값 비교시에 해당 값이 있는 요소가 하나라도 일치하면 true가 되지만 every는 전 요소가 모두 주어진 조건에 일치해야만 true가 됩니다.

Select @MyXml.value('every $s in /TopEle/Department/Names satisfies $s/@Nm="Sales"', 'Char(50)');

Nm속성이 "Sales"라고 되어 있는건 Department/Names의 세번째 요소에서만 일치하므로 결과는 false입니다.


3. exist

values로는 값이 있는지 없는지를 확인할 수 있지만 exist는 요소자체가 있는지 없는지를 판단할 수 있습니다.

Select @MyXml.exist('/TopEle/Department');

/TopEle요소 하위에 Department요소가 있는지 판단한 후 있으면 1 없으면 0을 반환합니다.


4. modify

XML에 접근하여 실제 XML Data를 추가/변경/삭제 할 수 있는 mothod입니다.

(1) 추가

Set @MyXml.modify('insert <newstart>spadework</newstart> as first into /');
Set @MyXml.modify('insert <newend>spadework</newend> as last into /');

<newstart>spadework</newstart>요소와 값을 해당 XML Data의 가장 처음(as first into)에 추가하고 <newend>spadework</newend>를 해당 XML Data의 가장 마지막(as last into)에 추가합니다.


Set @MyXml.modify('insert <TopEle mytag="new"/> as first into /TopEle[1]');

<TopEle mytag="new"/>요소와 속성을 TopEle요소의 처음부분에 추가합니다.


Set @MyXml.modify('insert <TopEle mytag="new"/> as last into /TopEle[1]/Department[3]');

<TopEle mytag="new"/>요소와 속성을 TopEle/Department 3번째 요소의 마지막에 추가합니다.


(2) 변경

Set @MyXml.modify('replace value of /TopEle[1]/Department[3]/Names[1]/@Nm with "abc"');

replace value of 를 통해 TopEle/Department 세번째요소의 Names요소에서 Nm속성값을 abc로 변경합니다.


(3) 삭제

Set @MyXml.modify('delete /TopEle[1]/Department[2]');

delete를 통해 /TopEle/Department 2번째 요소 전체를 삭제하도록 합니다.

0 0
Programming/Microsoft SQL Server
1. 숫자(정수)

 데이터형  크기  범위
 Begint  8byte  -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
 Int  4byte  -2,147,483,648 ~ -2,147,483,647
 Tinyint  2byte  0 ~ 255
 Bit  1byte  1, 0, Null
 Smallint  4byte  -32,768 ~ 32,767

2. 실수

(1) 고정형(Decimal, Numeric)
크기및 범위 : Numeric(전체크기, 소수점이하크기)

만일 Numeric(12, 2)라고 한다면 전체가 12자리이고 그 중에서 소수점이 2자리임을 의미합니다. 이때 전체크기가 1~9라면 5 byte, 10~19라면 9 byte, 20~28이라면 13 byte의 크기를 갖게 됩니다. 즉, 전체자리가 위와같이 증가한다면 크기는 4byte씩 늘어나는 것입니다.

또한 사용상 Decimal과 Numeric은 차이가 없습니다.

(2) 부동형실수(Float, Real)
크기및 범위 : Float(숫자)

Float에는 얼마만큼의 숫자가 들어가느냐에 따라 표현가능한 자리수가 달라집니다. 일반적으로 1~24까지 7자리(4 byte), 25~53까지 15자리(8 byte)표현이 가능합니다.

Real은 Float(24)와 같으며 7자리까지만 표현이 가능합니다.

Float과 Real은 상당히 큰 숫자를 다룰 수 있지만 근사치 데이터를 저장하는데, 실수를 다르는 경우 되도록 Decimal을 사용하는 것이 좋습니다.

3. 통화(통화형식은 소수점 이하 4자리수까지로 제한합니다.)

 데이터형  크기  범위
 Money  8byte  -922,337,203,685,477.5808 ~ 922,337,203,685,477.5807
 Smallmoney  4byte  -214,748.3648 ~ 214,748.3647

4. 문자(문자열)

 데이터형  크기  범위
 Char(n) / NChar(n)  입력된 n byte / 입력된 n * 2 byte  8000자 이하 / 4000자 이하
 Varchar(n) / NVarchar(n)  n에 입력된 크기와 상관없이 실제 사용된 만큼  8000자 이하 / 4000자 이하, MAX지정시 2기가 / 1,073,741,823자(단 MAX는 MS SQL 2008버전부터는 사용되지 않습니다.)
 Text / NText  231-1 byte / 230-1 byte  2,147,483,647자 / 1,073,741,823자

Text 나 NText 그리고 Image는 더이상 MS SQL Server에서 지원하지 않을 예정이니 사용하지 말고 대신 VarChar(Max), nVarChar(Max), Varbinary(Max)를 사용하는 것이 좋습니다.

Char는 고정형입니다. 예를 들어 Char(100)이라고 하면 100바이트 크기를 나타냅니다. 'abc'문자열을 저장하는 경우 3바이트만을 필요로 하지만 100중 3만 차지하고 나머지 97바이트는 버려집니다. 반면 VarChar는 가변형식으로서 VarChar(100)을 하더라도 'abc'를 저장할때는 3바이트만을 차지하기 때문에 공간효휼성은 더 좋습니다. 다만 성능은 Char형이 더 우위에 있습니다.

참고:
n으로 시작되는 형식은 유니코드문자용입니다.(대부분의 경우 크기는 n이 없는 형의 * 2 가 되며 저장할 수 있는 크기는 n이 없는 형의 절반입니다.)

5. 날짜형식

 데이터형  크기  범위
 Datetime  8byte  1753-01-01 ~ 9999-12-31(ms단위까지)
 SmallDateTime  4byte  1990-01-01 ~ 2079-06-09(분까지)

참고 :
년도를 4자리로 하지 않고 두자리만 지정시 년도는 다음과 같이 인식됩니다.
00 ~ 49 까지 : 2000년대
50 ~ 99 까지 : 1900년대

6. 이진형식

 데이터형  범위
 Binary(n) / VarBinary(n)  1~8000까지의 이진데이터(n을 생략시 1, cast에서 지정하지 않으면 30을 기본)
 Image  232-1byte(2,147,483,647 byte까지)

7. 시스템 형식

 데이터형  설명
 Cursor  커서
 Sql_Variant  IMAGE, NTEXT, NVARCHAR(MAX), TEXT, TIMESTAMP, VARCHAR(MAX), XML를 제외한 모든 자료형 대체가능
 Table  Table
 TimeStamp  TABLE의 행이 바뀔때마다 바뀌는 고유한 숫자(8 byte)
 Uniqueidentifier  Newid()를 통해 발생되는 고유값으로 16진수로 구성된 각 자리수가 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx형태로 구성되며 IS NULL이나 IS NOT NULL, =, <=, >=, <>, >, < 의 연산자만 허용합니다.
 Xml  Xml

8. 사용자 형식

(1) sp_addtype

sp_addtype 이름, '데이터형', null 여부, '소유자' 의 형태로 씁니다. null여부와 소유자는 생략할 수 있는데 이경우 null허용하게 되며 해당 데이터형은 현재사용자가 소유자가 되는것이 기본입니다.

sp_addtype postal, 'Char(07)';
Go

Declare @ipostal As postal;
Set @ipostal = '780-080';
Select @ipostal;


지정한 사용자 형식을 삭제하는 방법은 다음과 같습니다.

sp_droptype postal;

(2) Create Type

Create Type은 sp_addtype에 비해 소유자를 지정할 수 없을뿐 sp_addtype과 같습니다.
사용형식은 'Create Type 이름 From 데이터형, null 여부'로 구현됩니다.

Create Type postal From Char(07) Not Null;
Go

Declare @ipostal As postal;
Set @ipostal = '780-080'
Select @ipostal;


지정한 사용자 형식을 삭제하는 방법은 다음과 같습니다.

Drop Type postal;


9. ISO 표준 형식


MS SQL Server는 ISO와의 호환을 위해 다음 단어를 해당 형식으로 일치시켰습니다. 따라서 Char대신 Character를 사용할 수 있습니다.


 본래형식

 ISO형식

 Char

 Character

 VarChar

 Character Varying

 Varbinary

 Binary Varying

 Decimal

 Dec

 Float

 Double Precision

 Int

 Integer

 nChar

 National Character

 nVarChar

 National Character Varying

 RowVersion

 Timestamp


2 0
1
블로그 이미지

클리엘