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ß