ReadXmlExample

此示例逐个节点读取 XML 节点。

ReadXml.cpp

//------------------------------------------------------------
// Copyright (C) Microsoft.  All rights reserved.
//------------------------------------------------------------

#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
#include "WebServices.h"
#include "process.h"
#include "string.h"

#pragma comment(lib, "WebServices.lib")
#pragma comment(lib, "Rpcrt4.lib")

// Print out rich error info
void PrintError(HRESULT errorCode, WS_ERROR* error)
{
    wprintf(L"Failure: errorCode=0x%lx\n", errorCode);

    if (errorCode == E_INVALIDARG || errorCode == WS_E_INVALID_OPERATION)
    {
        // Correct use of the APIs should never generate these errors
        wprintf(L"The error was due to an invalid use of an API.  This is likely due to a bug in the program.\n");
        DebugBreak();
    }

    HRESULT hr = NOERROR;
    if (error != NULL)
    {
        ULONG errorCount;
        hr = WsGetErrorProperty(error, WS_ERROR_PROPERTY_STRING_COUNT, &errorCount, sizeof(errorCount));
        if (FAILED(hr))
        {
            goto Exit;
        }
        for (ULONG i = 0; i < errorCount; i++)
        {
            WS_STRING string;
            hr = WsGetErrorString(error, i, &string);
            if (FAILED(hr))
            {
                goto Exit;
            }
            wprintf(L"%.*s\n", string.length, string.chars);
        }
    }
Exit:
    if (FAILED(hr))
    {
        wprintf(L"Could not get error string (errorCode=0x%lx)\n", hr);
    }
}

void PrintString(const WS_XML_STRING* string)
{
    if (string->length == 0)
    {
        return;
    }

    WCHAR* chars = NULL;
    int charCount = 0;

    charCount = 
        MultiByteToWideChar(
        CP_UTF8, 
        MB_ERR_INVALID_CHARS, 
        (char*)string->bytes, 
        string->length, NULL, 0);
    if (charCount == 0)
    {
        printf("<error: MultiByteToWideChar failed>");
        goto Exit;
    }

    chars = (WCHAR*)HeapAlloc(
        GetProcessHeap(), 
        0, 
        charCount * sizeof(WCHAR));

    if (chars == NULL)
    {
        printf("<error: HeapAlloc failed>");
        goto Exit;
    }

    if (MultiByteToWideChar(
        CP_UTF8,
        MB_ERR_INVALID_CHARS, 
        (char*)string->bytes, string->length,
        chars, charCount) != charCount)
    {
        printf("<error: MultiByteToWideChar failed>");
        goto Exit;
    }

    printf("%.*S", charCount, chars);

Exit:
    if (chars != NULL)
    {
        HeapFree(GetProcessHeap(), 0, chars);
    }
}

void PrintText(const WS_XML_TEXT* text)
{
    switch (text->textType)
    {
        case WS_XML_TEXT_TYPE_UTF8:
            {
                const WS_XML_UTF8_TEXT* utf8Text = (const WS_XML_UTF8_TEXT*) text;
                printf("WS_XML_TEXT_TYPE_UTF8(value='");
                PrintString(&utf8Text->value);
                printf("')");
            }
            break;
        case WS_XML_TEXT_TYPE_UTF16:
            {
                const WS_XML_UTF16_TEXT* utf16Text = (const WS_XML_UTF16_TEXT*) text;
                printf("WS_XML_TEXT_TYPE_UTF16(value='%.*S')", utf16Text->byteCount / sizeof(WCHAR), (WCHAR*)utf16Text->bytes);
            }
            break;
        case WS_XML_TEXT_TYPE_BASE64:
            {
                const WS_XML_BASE64_TEXT* base64Text = (const WS_XML_BASE64_TEXT*) text;
                printf("WS_XML_TEXT_TYPE_BASE64(value={ ");
                for (ULONG i = 0; i < base64Text->length; i++)
                {
                    printf("%02x", base64Text->bytes[i]);
                }
                printf(" })");
            }
            break;
        case WS_XML_TEXT_TYPE_BOOL:
            {
                const WS_XML_BOOL_TEXT* boolText = (const WS_XML_BOOL_TEXT*) text;
                printf("WS_XML_TEXT_TYPE_BOOL(value='%s')", boolText->value ? "true" : "false");
            }
            break;
        case WS_XML_TEXT_TYPE_INT32:
            {
                const WS_XML_INT32_TEXT* int32Text = (const WS_XML_INT32_TEXT*) text;
                printf("WS_XML_TEXT_TYPE_INT32(value='%d')", int32Text->value);
            }
            break;
        case WS_XML_TEXT_TYPE_INT64:
            {
                const WS_XML_INT64_TEXT* int64Text = (const WS_XML_INT64_TEXT*) text;
                printf("WS_XML_TEXT_TYPE_INT64(value='%I64d')", int64Text->value);
            }
            break;
        case WS_XML_TEXT_TYPE_UINT64:
            {
                const WS_XML_UINT64_TEXT* uint64Text = (const WS_XML_UINT64_TEXT*) text;
                printf("WS_XML_TEXT_TYPE_UINT64(value='%I64u')", uint64Text->value);
            }
            break;
        case WS_XML_TEXT_TYPE_FLOAT:
            {
                const WS_XML_FLOAT_TEXT* floatText = (const WS_XML_FLOAT_TEXT*) text;
                printf("WS_XML_TEXT_TYPE_FLOAT(value='%f')", floatText->value);
            }
            break;
        case WS_XML_TEXT_TYPE_DOUBLE:
            {
                const WS_XML_DOUBLE_TEXT* doubleText = (const WS_XML_DOUBLE_TEXT*) text;
                printf("WS_XML_TEXT_TYPE_DOUBLE(value='%f')", doubleText->value);
            }
            break;
        case WS_XML_TEXT_TYPE_DECIMAL:
            {
                const WS_XML_DECIMAL_TEXT* decimalText = (const WS_XML_DECIMAL_TEXT*) text;
                const DECIMAL* dec = &decimalText->value;
                printf("WS_XML_TEXT_TYPE_DECIMAL(value={%x %x %x, %I64x})", dec->wReserved, dec->signscale, dec->Hi32, dec->Lo64);
            }
            break;
        case WS_XML_TEXT_TYPE_GUID:
            {
                WS_XML_GUID_TEXT* guidText = (WS_XML_GUID_TEXT*) text;
                RPC_WSTR s;
                if (UuidToString(&guidText->value, &s) == RPC_S_OK)
                {
                    printf("WS_XML_TEXT_TYPE_GUID(value='%ls')", s);
                    RpcStringFree(&s);
                }
                else
                {
                    printf("WS_XML_TEXT_TYPE_GUID(value='<error: UuidToString failed>')");
                }
            }
            break;
        case WS_XML_TEXT_TYPE_UNIQUE_ID:
            {
                WS_XML_UNIQUE_ID_TEXT* uniqueIdText = (WS_XML_UNIQUE_ID_TEXT*) text;
                RPC_WSTR s;
                if (UuidToString(&uniqueIdText->value, &s) == RPC_S_OK)
                {
                    printf("WS_XML_TEXT_TYPE_UNIQUEID(value='%ls')", s);
                    RpcStringFree(&s);
                }
                else
                {
                    printf("WS_XML_TEXT_TYPE_UNIQUEID(value='<error: UuidToString failed>')");
                }
            }
            break;
        case WS_XML_TEXT_TYPE_DATETIME:
            {
                const WS_XML_DATETIME_TEXT* dateTimeText = (const WS_XML_DATETIME_TEXT*)text;
                WS_DATETIME value = dateTimeText->value;
                printf("WS_XML_DATETIME_TEXT(ticks='%I64u',format='%d')", value.ticks, value.format);
            }
            break;
        case WS_XML_TEXT_TYPE_TIMESPAN:
            {
                const WS_XML_TIMESPAN_TEXT* timeSpanText = (const WS_XML_TIMESPAN_TEXT*)text;
                printf("WS_XML_TIMESPAN_TEXT(value='%I64u')", timeSpanText->value.ticks);
            }
            break;
        case WS_XML_TEXT_TYPE_QNAME:
            {
                const WS_XML_QNAME_TEXT* qnameText = (const WS_XML_QNAME_TEXT*)text;
                printf("WS_XML_QNAME_TEXT(prefix='"); 
                PrintString(qnameText->prefix);
                printf("', localName='"); 
                PrintString(qnameText->localName);
                printf("', ns='"); 
                PrintString(qnameText->ns);
                printf("')");
            }
            break;
        case WS_XML_TEXT_TYPE_LIST:
            {
                const WS_XML_LIST_TEXT* listText = (const WS_XML_LIST_TEXT*)text;
                printf("WS_XML_LIST_TEXT(value={");
                for (ULONG i = 0; i < listText->itemCount; i++)
                {
                    PrintText(listText->items[i]);
                    printf(" ");
                }
                printf("}");
            }
            break;
        default:
            printf("<error: Unexpected textType>");
            break;
    }
}

// Main entry point
int __cdecl wmain(int argc, __in_ecount(argc) wchar_t **argv)
{
    UNREFERENCED_PARAMETER(argc);
    UNREFERENCED_PARAMETER(argv);
    
    HRESULT hr = NOERROR;
    WS_ERROR* error = NULL;
    WS_XML_READER* xmlReader = NULL;
    
    // Create an error object for storing rich error information
    hr = WsCreateError(
        NULL, 
        0, 
        &error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    // Create an XML reader
    hr = WsCreateReader(
        NULL,
        0, 
        &xmlReader, 
        error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    char* xml = 
    "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>"
    "<Orders xmlns='http://example.com'>"
        "<!-- Order #1 -->"
        "<PurchaseOrder id='1'>"
            "<Quantity>42</Quantity>"
            "<ProductName>Toaster</ProductName>"
        "</PurchaseOrder>"
        "<!-- Order #2 -->"
        "<PurchaseOrder id='2'>"
            "<Quantity>5</Quantity>"
            "<ProductName><![CDATA[Block&Tackle]></ProductName>"
        "</PurchaseOrder>"
    "</Orders>";
    BYTE* bytes = (BYTE*) xml;
    ULONG byteCount = (ULONG)strlen(xml);
    
    // Setup the source input
    WS_XML_READER_BUFFER_INPUT bufferInput;
    ZeroMemory(&bufferInput, sizeof(bufferInput));
    bufferInput.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER;
    bufferInput.encodedData = bytes;
    bufferInput.encodedDataSize = byteCount;
    
    // Setup the source encoding
    WS_XML_READER_TEXT_ENCODING textEncoding;
    ZeroMemory(&textEncoding, sizeof(textEncoding));
    textEncoding.encoding.encodingType = WS_XML_READER_ENCODING_TYPE_TEXT;
    textEncoding.charSet = WS_CHARSET_AUTO;
    
    // Setup the reader
    hr = WsSetInput(xmlReader, &textEncoding.encoding, &bufferInput.input, NULL, 0, error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    WS_CHARSET charSet;
    hr = WsGetReaderProperty(xmlReader, WS_XML_READER_PROPERTY_CHARSET, &charSet, sizeof(charSet), error);
    if (FAILED(hr))
    {
        goto Exit;
    }
    
    switch (charSet)
    {
        case WS_CHARSET_UTF8:
            printf("charSet=utf-8\n");
            break;
        case WS_CHARSET_UTF16LE:
            printf("charSet=utf-16LE\n");
            break;
        case WS_CHARSET_UTF16BE:
            printf("charSet=utf-16BE\n");
            break;
        default:
            printf("<error: Unexpected charset>\n");
            hr = E_FAIL;
            goto Exit;
    }
    
    ULONG depth = 0;
    for (;;)
    {
        // Get the current node of the reader
        const WS_XML_NODE* node;
        hr = WsGetReaderNode(xmlReader, &node, error);
        if (FAILED(hr))
        {
            goto Exit;
        }
        for (ULONG i = 0; i < depth; i++)
        {
            printf(" ");
        }
        // Print out the type of node and its contents
        switch (node->nodeType)
        {
        case WS_XML_NODE_TYPE_ELEMENT:
            {
                const WS_XML_ELEMENT_NODE* elementNode = (const WS_XML_ELEMENT_NODE*) node;
                printf("WS_XML_NODE_TYPE_ELEMENT(prefix='");
                PrintString(elementNode->prefix);
                printf("', localName='");
                PrintString(elementNode->localName);
                printf("', ns='");
                PrintString(elementNode->ns);
                printf("', attributes={");
                for (ULONG i = 0; i < elementNode->attributeCount; i++)
                {
                    if (i != 0)
                    {
                        printf(", ");
                    }
                    const WS_XML_ATTRIBUTE* attribute = elementNode->attributes[i];
                    if (attribute->isXmlNs)
                    {
                        printf("(isXmlNs=TRUE, prefix='");
                        PrintString(attribute->prefix);
                        printf("', ns='");
                        PrintString(attribute->ns);
                        printf("')");
                    }
                    else
                    {
                        printf("(isXmlNs=FALSE, prefix='");
                        PrintString(attribute->prefix);
                        printf("', localName='");
                        PrintString(attribute->localName);
                        printf("', ns='");
                        PrintString(attribute->ns);
                        printf("', value=");
                        PrintText(attribute->value);
                        printf(")");
                    }
                }
                printf("})\n");
            }
            depth++;
            break;
        case WS_XML_NODE_TYPE_END_ELEMENT:
            printf("WS_XML_NODE_TYPE_END_ELEMENT\n");
            depth--;
            break;
        case WS_XML_NODE_TYPE_TEXT:
            {
                const WS_XML_TEXT_NODE* textNode = (const WS_XML_TEXT_NODE*) node;
                printf("WS_XML_NODE_TYPE_TEXT(value=");
                PrintText(textNode->text);
                printf(")\n");
            }
            break;
        case WS_XML_NODE_TYPE_CDATA:
            printf("WS_XML_NODE_TYPE_CDATA\n");
            depth++;
            break;
        case WS_XML_NODE_TYPE_END_CDATA:
            printf("WS_XML_NODE_TYPE_END_CDATA\n");
            depth--;
            break;
        case WS_XML_NODE_TYPE_COMMENT:
            {
                const WS_XML_COMMENT_NODE* commentNode = (const WS_XML_COMMENT_NODE*) node;
                printf("WS_XML_NODE_TYPE_COMMENT(value='");
                PrintString(&commentNode->value);
                printf("')\n");
            }
            break;
        case WS_XML_NODE_TYPE_BOF:
            printf("WS_XML_NODE_TYPE_BOF\n");
            depth++;
            break;
        case WS_XML_NODE_TYPE_EOF:
            printf("WS_XML_NODE_TYPE_EOF\n");
            depth--;
            break;
        default:
            printf("<error: Unexpected nodeType>\n");
            hr = E_FAIL;
            goto Exit;
        }
        // See if we've reached the end of the document
        if (node->nodeType == WS_XML_NODE_TYPE_EOF)
        {
            break;
        }
        // Advance the reader
        hr = WsReadNode(xmlReader, error);
        if (FAILED(hr))
        {
            goto Exit;
        }
    }
    
Exit:
    if (FAILED(hr))
    {
        // Print out the error
        PrintError(hr, error);
    }
    fflush(
        stdout);
    
    if (xmlReader != NULL)
    {
        WsFreeReader(xmlReader);
    }
    if (error != NULL)
    {
        WsFreeError(error);
    }
    fflush(stdout);
    return SUCCEEDED(hr) ? 0 : -1;
}