XML, Schemas und DOM



  • Hallo,
    ich habe eine XML Datei und ein dazugehöriges XSD Schema. Nun will ich zu den bestehenden Einträgen einen weiteren erzeugen, doch das klappt nicht. Ich kann irgendwie nur die bestehenden clonen und abändern, aber nicht einfach neue erzeugen. Der Witz an der Geschichte ist, klappen tut es eigtl. schon, nach dem speichern ist die XML schon richtig, aber das Doc lässt sich nicht validieren und dann funktioniert die Suche nach dem entsprechenden Node eben nicht. Ich füge jetzt mal mein Beispiel ein, vielleich hatte ja schon jemand ähnliche Problem, und bitte nicht meckern wegen Sprungmarken und Ähnlichem, das meiste davon hab direkt von der Microsoft Online Doku kopiert.

    XML

    <?xml version="1.0" standalone="yes"?>
    <MYXML xmlns="http://tempuri.org/MYXML.xsd">
    	<Values d2p1:ID="1" d2p1:Name="Maier" xmlns:d2p1="http://tempuri.org/MYXML.xsd"/>
    	<Values d2p1:ID="2" d2p1:Name="Mueller" xmlns:d2p1="http://tempuri.org/MYXML.xsd"/>
    	<Values d2p1:ID="3" d2p1:Name="Mustermann" xmlns:d2p1="http://tempuri.org/MYXML.xsd"/>
    	<Values d2p1:ID="4" d2p1:Name="Schmidt" xmlns:d2p1="http://tempuri.org/MYXML.xsd"/>
    </MYXML>
    

    XSD

    <?xml version="1.0" encoding="utf-8" ?>
    <xs:schema id="MYXML" targetNamespace="http://tempuri.org/MYXML.xsd" elementFormDefault="qualified"
    	attributeFormDefault="qualified" xmlns="http://tempuri.org/MYXML.xsd" xmlns:mstns="http://tempuri.org/MYXML.xsd"
    	xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    	<xs:element name="MYXML" msdata:IsDataSet="true">
    		<xs:complexType>
    			<xs:choice maxOccurs="unbounded">
    				<xs:element name="Values">
    					<xs:complexType>
    						<xs:sequence></xs:sequence>
    						<xs:attribute name="ID" type="xs:string" />
    						<xs:attribute name="Name" type="xs:string" />
    					</xs:complexType>
    				</xs:element>
    			</xs:choice>
    		</xs:complexType>
    		<xs:key name="MYXMLKey1" msdata:PrimaryKey="true">
    			<xs:selector xpath=".//mstns:Values" />
    			<xs:field xpath="@mstns:ID" />
    		</xs:key>
    	</xs:element>
    </xs:schema>
    

    Beispiel

    #import <msxml6.dll>
    
    // Macro that calls a COM method returning HRESULT value.
    #define CHK_HR(stmt)        do{ hr=(stmt); if (FAILED(hr)) goto CleanUp; } while(0)
    
    void dump_com_error(_com_error &e)
    {
        _bstr_t bstrSource(e.Source());
        _bstr_t bstrDescription(e.Description());
    
        printf("Error(dump_com_error)\n");
        printf("\tCode = %08lx\n", e.Error());
        printf("\tCode meaning = %s", e.ErrorMessage());
        printf("\tSource = %s\n", (LPCSTR) bstrSource);
        printf("\tDescription = %s\n", (LPCSTR) bstrDescription);
    }
    
    void validateXML()
    {
    	MSXML2::IXMLDOMDocument3Ptr         pXMLDoc;
        MSXML2::IXMLDOMDocument2Ptr         pXSDDoc;
        MSXML2::IXMLDOMParseErrorPtr        pError;
        MSXML2::IXMLDOMSchemaCollectionPtr  pSCache;
        MSXML2::IXMLDOMNodePtr              pNode;
        MSXML2::IXMLDOMNodeListPtr          pNodelist;
        HRESULT                             hr = S_OK;
    
        try
        {
    		// Load books.xml into a DOM instance.
            CHK_HR(pXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60), NULL, CLSCTX_INPROC_SERVER));
    
            pXMLDoc->async = VARIANT_FALSE;
            pXMLDoc->validateOnParse = VARIANT_FALSE;
    
            if(pXMLDoc->load(L"D:\\Uebung\\NodeInsertingTest\\Debug\\MYXML.xml") != VARIANT_TRUE)
            {
                printf("Cannot load books.xml to DOMDocument object.\n");
                CHK_HR(pXMLDoc->parseError->errorCode);
            }
    
            // Load books.xsd into a DOM instance.
            CHK_HR(pXSDDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60), NULL, CLSCTX_INPROC_SERVER));
    
            pXSDDoc->async = VARIANT_FALSE;
            pXSDDoc->validateOnParse = VARIANT_FALSE;
    
            if(pXSDDoc->load(L"D:\\Uebung\\NodeInsertingTest\\Debug\\MYXML.xsd") != VARIANT_TRUE)
            {
                printf("Cannot load books.xsd to DOMDocument object.\n");
                CHK_HR(pXSDDoc->parseError->errorCode);
            }
    
    		pXMLDoc->setProperty(L"SelectionNamespaces", L"xmlns:d2p1='http://tempuri.org/MYXML.xsd'");
    
            // Create a schema cache instance.
            CHK_HR(pSCache.CreateInstance(__uuidof(MSXML2::XMLSchemaCache60), NULL, CLSCTX_INPROC_SERVER));
            // Add the just-loaded schema definition to the schema collection.
            CHK_HR(pSCache->add(L"http://tempuri.org/MYXML.xsd", pXSDDoc.GetInterfacePtr()));
            // Associate the schema collection with the XMLDoc instance. 
            pXMLDoc->schemas = pSCache.GetInterfacePtr();
    
            // Validate the entire DOM.
            printf("Validating DOM...\n");
    
            pError = pXMLDoc->validate();
            if (pError->errorCode != 0)
            {
                printf("\tXMLDoc is not valid because\n%s\n", (LPCSTR)pError->Getreason());
            }
            else
            {
                printf("\tXMLDoc is validated: \n%s\n", (LPCSTR)pXMLDoc->xml);
            }
    
    		//Node mit ID=1 suchen
    		pNode = pXMLDoc->selectSingleNode(L"//d2p1:Values[@d2p1:ID='1']");
    		pError = pXMLDoc->validateNode(pNode);
    		if (pError->errorCode != 0)
            {
                printf("\t<%s> is not valid because\n%s\n", (LPCSTR)pNode->nodeName, (LPCSTR)pError->Getreason());
            }
    
    		//Clone erzeugen und einfügen
    		VARIANT_BOOL bdeep = VARIANT_TRUE;
    
    		MSXML2::IXMLDOMElementPtr pCloneElement = pNode->cloneNode(bdeep);
    		pCloneElement->setAttribute(L"d2p1:ID", L"5");
    		pCloneElement->setAttribute(L"d2p1:Name", L"Becker");
    
    		MSXML2::IXMLDOMNodePtr pRootNode = pXMLDoc->GetdocumentElement();
    		printf("%s %s\n", (LPCSTR)pRootNode->nodeName, (LPCSTR)pRootNode->text);
    
    		pRootNode->appendChild(pCloneElement);
    
    		//Clone validieren
    		pError = pXMLDoc->validateNode(pCloneElement);
    		if (pError->errorCode != 0)
            {
                printf("\t<%s> is not valid because\n%s\n", (LPCSTR)pNode->nodeName, (LPCSTR)pError->Getreason());
            }
    
    		//XML speichern
    		_bstr_t curPath = pXMLDoc->Geturl();
    		_variant_t v((LPSTR)curPath);
    		pXMLDoc->save(v);
    
    		//Doc validieren
    		pError = pXMLDoc->validate(); 
            if (pError->errorCode != 0)
            {
                printf("\tXMLDoc is not valid because\n%s\n", (LPCSTR)pError->Getreason());
            }
            else
            {
                printf("\tXMLDoc is validated: \n%s\n", (LPCSTR)pXMLDoc->xml);
            }
    
    		//Neues Element erzeugen
    		MSXML2::IXMLDOMElementPtr pNewElement = pXMLDoc->createNode(_variant_t((short)MSXML2::NODE_ELEMENT), L"Values", L"http://tempuri.org/MYXML.xsd");
    
    		//Die Attribute erzeugen und hinzufuegen
    		MSXML2::IXMLDOMAttributePtr  pXMLAttribute1 = pXMLDoc->createAttribute(L"d2p1:ID");
    		pXMLAttribute1->value = L"6";
    
    		MSXML2::IXMLDOMAttributePtr  pXMLAttribute2 = pXMLDoc->createAttribute(L"d2p1:Name");
    		pXMLAttribute2->value = L"Hase";
    
    		MSXML2::IXMLDOMAttributePtr  pXMLAttribute3 = pXMLDoc->createAttribute(L"xmlns:d2p1");
    		pXMLAttribute3->value = L"http://tempuri.org/MYXML.xsd";
    
    		pNewElement->setAttributeNode(pXMLAttribute1);
    		pNewElement->setAttributeNode(pXMLAttribute2);
    		pNewElement->setAttributeNode(pXMLAttribute3);
    
    		//Hinzufuegen
    		pRootNode->appendChild(pNewElement);
    
    		//Neues Element validieren
    		pError = pXMLDoc->validateNode(pNewElement);
    		if (pError->errorCode != 0)
            {
                printf("\t<%s> is not valid because\n%s\n", (LPCSTR)pNewElement->nodeName, (LPCSTR)pError->Getreason());
            }
    
    		//XML speichern
    		pXMLDoc->save(v);
    
    		//Doc validieren
    		pError = pXMLDoc->validate(); 
            if (pError->errorCode != 0)
            {
                printf("\tXMLDoc is not valid because\n%s\n", (LPCSTR)pError->Getreason());
            }
            else
            {
                printf("\tXMLDoc is validated: \n%s\n", (LPCSTR)pXMLDoc->xml);
            }
    
    	}
        catch(_com_error &e)
        {
            dump_com_error(e);
        }
    
    CleanUp:
        return;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	CoInitialize(NULL);
    
    	validateXML();
     CoUninitialize();
    
    	return 0;
    }
    

    Wie erzeugt man denn so ein Element richtig ?

    MfG



  • Aus der MSDN:

    You cannot create a namespace-qualified attribute using the createAttribute method. Regardless of whether a namespace prefix is included in the name parameter, the namespaceURI property for the new attribute is set to an empty string, "". An attribute constructed as part of an XML document load operation will never have both a prefix and an empty namespace Uniform Resource Identifier (URI). You can only create a namespace-qualified attribute using the createNode method of the DOMDocument.



  • Hallo, vielen Dank erst mal, hätte ich das gefunden, wäre vieles schneller gewesen, hier noch die funktionierende Variante für alle, die es auch noch interessiert:

    //Neues Element erzeugen
    MSXML2::IXMLDOMElementPtr pNewElement = pXMLDoc->createNode(_variant_t((short)MSXML2::NODE_ELEMENT), pNode->nodeName, pNode->namespaceURI);
    
    MSXML2::IXMLDOMAttributePtr pXMLAttribute1 = pXMLDoc->createNode(_variant_t((short)MSXML2::NODE_ATTRIBUTE),  L"d2p1:ID", pNode->namespaceURI);
    pXMLAttribute1->value = L"6";
    
    MSXML2::IXMLDOMAttributePtr pXMLAttribute2 = pXMLDoc->createNode(_variant_t((short)MSXML2::NODE_ATTRIBUTE),  L"d2p1:Name", pNode->namespaceURI);
    pXMLAttribute2->value = L"Hase";
    
    MSXML2::IXMLDOMAttributePtr pXMLAttribute3 = pXMLDoc->createNode(_variant_t((short)MSXML2::NODE_ATTRIBUTE),  L"xmlns:d2p1", pNode->namespaceURI);
    pXMLAttribute3->value = L"http://tempuri.org/MYXML.xsd";
    
    pNewElement->setAttributeNode(pXMLAttribute1);
    pNewElement->setAttributeNode(pXMLAttribute2);
    pNewElement->setAttributeNode(pXMLAttribute3);
    

    Kaum macht mans richtig (oder zumindest besser) funktionierts, Danke nochmal

    Gruß


Anmelden zum Antworten