[gelöst] XMLDOM Namespace wird automatisch leer gesetzt

28. September 2012 12:27

Hallo Community,

ich bin grade dabei eine funktionieren DotNet Funktion, welche im NAV 2009 R2 gut funktioniert hat nachzubauen in NAV, weil der Kunde nicht von seiner SP1 runter kommt. Kurz um, die DotNet Funktion hat eigentlich nichts anderes gemacht als einen Webservice anzusprechen mit ein paar Parametern. Jetzt wird das ganze via MSXML DOM nachgebaut und dabei bekomme ich immer wieder den HTTP Fehler 500. Hier die Fakten:

SOAP 1.1 Anforderung an die XML DOM Struktur
Code:
POST ASMX DIR HTTP/1.1
Host: HOST
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://schemas.microsoft.com/sharepoint/soap/CopyIntoItems"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <CopyIntoItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">
      <SourceUrl>string</SourceUrl>
      <DestinationUrls>
        <string>string</string>
        <string>string</string>
      </DestinationUrls>
      <Fields>
        <FieldInformation Type="Invalid or Integer or Text or Note or DateTime or Counter or Choice or Lookup or Boolean or Number or Currency or URL or Computed or Threading or Guid or MultiChoice or GridChoice or Calculated or File or Attachments or User or Recurrence or CrossProjectLink or ModStat or AllDayEvent or Error" DisplayName="string" InternalName="string" Id="guid" Value="string" />
        <FieldInformation Type="Invalid or Integer or Text or Note or DateTime or Counter or Choice or Lookup or Boolean or Number or Currency or URL or Computed or Threading or Guid or MultiChoice or GridChoice or Calculated or File or Attachments or User or Recurrence or CrossProjectLink or ModStat or AllDayEvent or Error" DisplayName="string" InternalName="string" Id="guid" Value="string" />
      </Fields>
      <Stream>base64Binary</Stream>
    </CopyIntoItems>
  </soap:Body>
</soap:Envelope>


Mein Code:
Code:
IF ISCLEAR(XMLDoc) THEN
  CREATE(XMLDoc, TRUE, FALSE);

XMLMgt.SetNormalCase;
XMLProcInst := XMLDoc.createProcessingInstruction('xml','version="1.0" encoding="utf-8"');
XMLNode := XMLDoc.appendChild(XMLProcInst);

XMLNode := XMLDoc.createElement('soap:Envelope');
XMLMgt.AddAttribute(XMLNode,'xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance');
XMLMgt.AddAttribute(XMLNode,'xmlns:xsd','http://www.w3.org/2001/XMLSchema');
XMLMgt.AddAttribute(XMLNode,'xmlns:soap','http://www.w3.org/2003/05/soap-envelope');
XMLNode := XMLDoc.appendChild(XMLNode);

  XMLChildNode := XMLDoc.createElement('soap:Body');
  XMLNode.appendChild(XMLChildNode);
  XMLNode := XMLChildNode;

    XMLChildNode := XMLDoc.createElement('CopyIntoItems');
    XMLMgt.AddAttribute(XMLChildNode,'xmlns','http://schemas.microsoft.com/sharepoint/soap/');
    XMLNode.appendChild(XMLChildNode);
    XMLNode := XMLChildNode;

      XMLChildNode := XMLDoc.createElement('SourceURL');
      XMLChildNode.text := srcDocument;
      XMLNode.appendChild(XMLChildNode);

      XMLNodeDestination := XMLDoc.createElement('DestinationUrls');
      XMLNode.appendChild(XMLNodeDestination);

        XMLChildNode := XMLDoc.createElement('string');
        XMLChildNode.text := dstDocument;
        XMLNodeDestination.appendChild(XMLChildNode);

      XMLNodeFields := XMLDoc.createElement('Fields');
      XMLNode.appendChild(XMLNodeFields);

        XMLChildNode := XMLDoc.createElement('FieldInformation');
        XMLMgt.AddAttribute(XMLChildNode, 'Type', 'Text');
        XMLMgt.AddAttribute(XMLChildNode, 'DisplayName', 'Titel');
        XMLMgt.AddAttribute(XMLChildNode, 'InternalName', 'Titel');
        XMLMgt.AddAttribute(XMLChildNode, 'Id', FORMAT(CREATEGUID));
        XMLMgt.AddAttribute(XMLChildNode, 'Value', DocTitle);
        XMLNodeFields.appendChild(XMLChildNode);
     
        XMLChildNode := XMLDoc.createElement('FieldInformation');
        XMLMgt.AddAttribute(XMLChildNode, 'Type', 'Text');
        XMLMgt.AddAttribute(XMLChildNode, 'DisplayName', 'Dokumenttyp');
        XMLMgt.AddAttribute(XMLChildNode, 'InternalName', 'Dokumenttyp');
        XMLMgt.AddAttribute(XMLChildNode, 'Id', FORMAT(CREATEGUID));
        XMLMgt.AddAttribute(XMLChildNode, 'Value', DocType);
        XMLNodeFields.appendChild(XMLChildNode);

        XMLChildNode := XMLDoc.createElement('FieldInformation');
        XMLMgt.AddAttribute(XMLChildNode, 'Type', 'Text');
        XMLMgt.AddAttribute(XMLChildNode, 'DisplayName', DocKeyField);
        XMLMgt.AddAttribute(XMLChildNode, 'InternalName', DocKeyField);
        XMLMgt.AddAttribute(XMLChildNode, 'Id', FORMAT(CREATEGUID));
        XMLMgt.AddAttribute(XMLChildNode, 'Value', DocKeyValue);
        XMLNodeFields.appendChild(XMLChildNode);

      XMLChildNode := XMLDoc.createElement('Stream');
      IF ISCLEAR(Base64) THEN
        CREATE(Base64, TRUE, FALSE);
      Base64.Encode(srcDocument, XMLChildNode);
      XMLNode.appendChild(XMLChildNode);

//DEBUG
XMLDoc.save('C:\Users\KW5\Desktop\debug.xml');

IF ISCLEAR(XMLHttp) THEN
  CREATE(XMLHttp, TRUE, FALSE);

XMLHttp.open('POST',SPHostUrl + 'ASMX DIR',FALSE);
XMLHttp.setRequestHeader('Host','HOST');
XMLHttp.setRequestHeader('Content-Type','text/xml; charset=utf-8');
//XMLHttp.setRequestHeader('Content-Length', FORMAT(STRLEN(XMLDoc.xml))); Funktioniert nicht, da die STRING Länge zu lang ist oO?
XMLHttp.setRequestHeader('SOAPAction','http://schemas.microsoft.com/sharepoint/soap/CopyIntoItems');
XMLHttp.send(XMLDoc);


Das Ergebniss:
Code:
  <?xml version="1.0" encoding="utf-8" ?>
- <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
- <soap:Body>
- <CopyIntoItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">
  <SourceURL xmlns="">\\FILESERVER\TEST.pdf</SourceURL>
- <DestinationUrls xmlns="">
  <string>http://SHAREPOINT/TEST/TEST.pdf</string>
  </DestinationUrls>
- <Fields xmlns="">
  <FieldInformation Type="Text" DisplayName="Titel" InternalName="Titel" Id="{267EA026-FD6E-45BF-AB8E-3792ACC5800B}" Value="TEST.pdf" />
  <FieldInformation Type="Text" DisplayName="Dokumenttyp" InternalName="Dokumenttyp" Id="{70A42489-359D-474D-8A62-09B97A4ACAF3}" Value="TYPE" />
  <FieldInformation Type="Text" DisplayName="Kreditor" InternalName="Kreditor" Id="{0DA0F90E-3D47-4A39-8C6F-AD92C7FAF4BF}" Value="NO" />
  </Fields>
  <Stream xmlns="">JVBERi0xLjM..........CiUlRU9G</Stream>
  </CopyIntoItems>
  </soap:Body>
  </soap:Envelope>


ich hab den Base64Binary mal etwas gekürzt, da dass den Rahmen sprengt ;)

Wenn ich mich richtig in der XMLDOM Struktur auskenne, dann wird mit xmlns (XML Namespace) der Namespace gesetzt für alle ChildNodes, sofern man nicht den namen mit namespace:element deklariert. Wie man im Code sieht gebe ich dem Element CopyIntoItems den Namespace und danach keinen ChildNode. Ich vermute, dass ich den HTTP Fehler 500 deshalb bekomme, weil die in allen ChildNodes den Namespace zurückgesetzt bekomme. Könnte das evtl, das Problem sein und wieso setzt der Code den Namespace zurück? Kann ich evtl. einfach die Childnodes mit dem Namespace instanzieren ohne das dies Probleme mit dem Webservice hervorruft?

Es handelt sich dabei um MSXML 6.0 und für alle Interessierten, was das Base64 ist. Das ist die Automation "CG Request Client".Base64. Lange nach gesucht...
Zuletzt geändert von iPeon am 28. September 2012 15:17, insgesamt 1-mal geändert.

Re: XMLDOM Namespace wird automatisch leer gesetzt

28. September 2012 14:05

Hallo,

nicht eine direkte Antwort auf Deine Frage, aber wieso baust Du den SOAP Request nicht unter Verwendung der 'Microsoft Soap Type Library' aus MSSOAP-Toolkit. Mit Verteilung der darin enthaltenen mssoap30.dll auf die betroffenen Maschinen lässt sich der SOAP-Request vermutlich gut in Navision umsetzen. Und hier lassen sich m.E. die Namespaces über den SOAPSerializer recht gut steuern.

In etwa so:

Code:
SOAPHttpConnector   Automation   'Microsoft Soap Type Library'.HttpConnector   
SOAPSerializer   Automation   'Microsoft Soap Type Library'.SoapSerializer   
SOAPReader   Automation   'Microsoft Soap Type Library'.SoapReader   
XMLElement   Automation   'Microsoft XML, v6.0'.IXMLDOMElement   

SOAPHttpConnector.Property('EndPointURL', EndPointURL);
SOAPHttpConnector.Connect;
SOAPHttpConnector.Property('AuthUser', myUser);
SOAPHttpConnector.Property('AuthPassword', MyPassword);
SOAPHttpConnector.Property('Timeout', 5000);
SOAPHttpConnector.Property('UseProxy','false');
SOAPHttpConnector.BeginMessage;

CREATE(SOAPSerializer);
SOAPSerializer.Init(SOAPHttpConnector.InputStream);
SOAPSerializer.startEnvelope('soapenv','http://schemas.xmlsoap.org/soap/encoding/');
SOAPSerializer.SoapNamespace('soapenv','http://schemas.xmlsoap.org/soap/envelope/');
SOAPSerializer.SoapNamespace('xsd','http://www.w3.org/2001/XMLSchema');
SOAPSerializer.SoapNamespace('xsi','http://www.w3.org/2001/XMLSchema-instance');

SOAPSerializer.startBody;
SOAPSerializer.startElement('CopyIntoItems ','http://schemas.microsoft.com/sharepoint/soap/');
SOAPSerializer.startElement('SourceUrl');
SOAPSerializer.writeString('string');
SOAPSerializer.endElement;
SOAPSerializer.startElement('DestinationUrls');
SOAPSerializer.startElement('string');
SOAPSerializer.writeString('string');
SOAPSerializer.endElement;
SOAPSerializer.endElement;
SOAPSerializer.endElement;

...und so weiter...

SOAPSerializer.endBody;
SOAPSerializer.endEnvelope;
SOAPHttpConnector.EndMessage;

CREATE(SOAPReader);
SOAPReader.Load(SOAPHttpConnector.OutputStream);
XMLElement := SOAPReader.BodyEntry('YourNode','NameSpaceOfYourNode');


Gruß
Meik

Re: XMLDOM Namespace wird automatisch leer gesetzt

28. September 2012 15:16

Ok probieren geht über studieren :)

Ich hab den Namespace einfach mal mit einem Namen versehen und dann überall selber dran gehangen. Damit bekomm ich den HTTP Status 200 wieder, leider noch ohne Response XML, aber das ist ein anderes Problem.

Hier der kleine Codeschnipsel, was ich abgeändert habe.
Code:
    XMLChildNode := XMLDoc.createElement('spf:CopyIntoItems');
    XMLMgt.AddAttribute(XMLChildNode,'xmlns:spf','http://schemas.microsoft.com/sharepoint/soap/');
    XMLNode.appendChild(XMLChildNode);
    XMLNode := XMLChildNode;

      XMLChildNode := XMLDoc.createElement('spf:SourceURL');
      XMLChildNode.text := srcDocument;
      XMLNode.appendChild(XMLChildNode);

      XMLNodeDestination := XMLDoc.createElement('spf:DestinationUrls');
      XMLNode.appendChild(XMLNodeDestination);

        XMLChildNode := XMLDoc.createElement('spf:string');
        XMLChildNode.text := dstDocument;
        XMLNodeDestination.appendChild(XMLChildNode);

      XMLNodeFields := XMLDoc.createElement('spf:Fields');
      XMLNode.appendChild(XMLNodeFields);

        XMLChildNode := XMLDoc.createElement('spf:FieldInformation');


@Meik: Danke für deine Idee, aber leider hab ích die dll nicht im Zugriff und kann es mir nicht als Automation einbauen. Dazu fehlen mir auch die Berechtigungen auf dem System wo ich dies implementieren soll.