Dataport, Umlaute, Probleme mit Code

11. Oktober 2006 16:53

Hallo Leute

Ich habe folgendes Problem: Ich exportiere via Dataport Artikeldaten. Wie ihr sicher wisst sind die im ASCII-Format und somit für mich unbrauchbar (Umlaute).
Nun gibts da so ein super Tool von Mister Lässer, ich weiss. Leider hier nicht brauchbar, da die erforderlichen Lizenzen fehlen(kann keine CodeUnits erstellen).
Nun könnte man das ja direkt auch beim Dataport selber programmieren, was ich auch machen wollte (hab noch ein Beispiel von unserem Navision Distributor bekommen).

Ich hab folgendes gemacht:

- Neuer Dataport welcher in die Datei c:\test.txt exportiert.
- Funktion "ASCII2ANSI" erstellt
- Parameter _Dateiname
- Variablen: Quellendatei, Zieldatei, TempDateiName, Z

Dazu folgender Code:

Code:
// Wandelt Datei von ASCII in ANSI um
TempDateiName := 'c:\temp.txt';

// Quellendatei temporär umbenennen und öffnen
IF EXISTS(TempDateiName) THEN
  ERASE(TempDateiName);
IF NOT RENAME(_Dateiname,TempDateiName) THEN
  ERROR('Datei %1 konnte nicht umbenannt werden.',_Dateiname);

Quellendatei.TEXTMODE := FALSE;
Quellendatei.WRITEMODE := FALSE;
Quellendatei.OPEN(TempDateiName);

// Zieldatei vorbereiten mit Original-Name
Zieldatei.TEXTMODE := FALSE;
Zieldatei.WRITEMODE := TRUE;
Zieldatei.CREATE(_Dateiname);

// Quellendatei zeichenweise lesen und neu schreiben
WHILE Quellendatei.READ(Z) = 1 DO BEGIN

  CASE Z OF
    132: Z := 228; // ä  ASCII=Alt132, ANSI = Alt0228
    142: Z := 196; // Ä
    131: Z := 226; // â
    133: Z := 224; // à
    160: Z := 225; // á
    134: Z := 229; // å
    143: Z := 197; // Å
    145: Z := 230; // æ
    146: Z := 198; // Æ

    128: Z := 199; // Ç
    135: Z := 231; // ç
   
    130: Z := 233; // é
    136: Z := 234; // ê
    137: Z := 235; // ë
    138: Z := 232; // è
    144: Z := 201; // É

    139: Z := 239; // ï
    140: Z := 238; // î
    141: Z := 236; // ì
    161: Z := 237; // í

    148: Z := 246; // ö
    153: Z := 214; // Ö
    147: Z := 244; // ô
    149: Z := 242; // ò
    162: Z := 243; // ó

    129: Z := 252; // ü
    154: Z := 220; // Ü
    150: Z := 251; // û
    151: Z := 249; // ù
    163: Z := 250; // ú

    164: Z := 241; // ñ
    165: Z := 209; // Ñ
    152: Z := 255; // ÿ
    156: Z := 163; // £
    157: Z := 248; // ø
  END;
  Zieldatei.WRITE(Z);
END;

Quellendatei.CLOSE;
IF NOT ERASE(TempDateiName) THEN
  ERROR('Temporäre Datei %1 konnte nicht gelöscht werden.',TempDateiName);



Das ganze wird dann bei OnPostDataport() aufgerufen

- Navision 3.6

- Wenn ich den Dataport jetzt ausführe, kommt immer die Meldung: "Datei C:\test.txt konnte nicht umbenannt werden." Wahrscheinlich ist sie noch von Navision geöffnet und Windows kann nicht darauf zugreifen... Theoretisch müsste es aber so gehen, denn ich hab den Code von unserem Navision Distributor, welcher den auch benützt ??
Naja, ich jedenfalls bin mit meinem Latein am Ende. Egal, was ich am Code ändere, ich werde immer mit Fehlermeldungen überschüttet...

Wäre nett, wenn sich das mal einer von euch Profis anschauen könnte. Vielleicht habt ihr ja eine Idee...
Wahrscheinlich hat unser Distributor absichtlich einen Fehler eingebaut, damit ich es von Ihnen gegen Bezahlung erledigen lasse :evil: :lol:

Gruess und schönen Abend
Marco

11. Oktober 2006 17:27

Navisionintern geht es auch und ohne Probleme :
Eine Textvariable Zielwert mit Länge 10 ( oder mehr, wenn weitere Sonderzeichen vorhanden sind) anlegen, die Funktion DOS2ANSI hat einen VAR -Parameter ANSIText ( Länge 250 ) und einen Text -Rückgabewert ( auch 250)


Diesen Abschnitt z.B in den OnPreDataport Trigger. Enthält schon die meisten gängigen Sonderzeichen, bei Bedarf erweitern : ANSI-Zeichensatz
Code:
Zielwert[1] := 196;
Zielwert[2] := 214;
Zielwert[3] := 220;
Zielwert[4] := 228;
Zielwert[5] := 246;
Zielwert[6] := 252;
Zielwert[7] := 223;
Zielwert[8] := 233;
Zielwert[9] := 225;
Zielwert[10] := 181;


Funktion :DOS2ANSI :

Code:
EXIT(CONVERTSTR(ANSItext,'ÄÖÜäöüßéáµ',Zielwert));


Dann im Code z.B.

Code:
Beschreibung := DOS2ANSI(Beschreibung);


vor dem Exportieren.
Zuletzt geändert von Kowa am 12. Oktober 2006 10:39, insgesamt 2-mal geändert.

11. Oktober 2006 18:44

Marco hat geschrieben:Leider hier nicht brauchbar, da die erforderlichen Lizenzen fehlen(kann keine CodeUnits erstellen).

Die ID der Codeunit (99996) kann in der Objekt-Textdatei mit einem einfachen Texteditor (wie z. B. Notepad) nach Belieben geändert werden.
Einfach eine ungenutzte lizensierte Codeunit-ID eintragen und schon lässt sich die Codeunit importieren.

Falls keine IDs mehr frei sein sollten, so kann die Funktion auch einfach in eine (lizensierte) Codeunit deiner Wahl kopiert werden.

Der Vorteil der Funktion in meiner Codeunit ist (abgesehen von der Vollständigkeit aller konvertierbaren Zeichen) ganz klar die Performance, denn wenn jedes Zeichen des Strings in einer Schleife einzeln konvertiert werden soll dauert dies ungefähr 8x länger als mit der CONVERTSTR-Methode.
Das habe ich schon mit einer riesigen Textdatei getestet. (Schleife: 16 Minuten, CONVERTSTR: 2 Minuten)

11. Oktober 2006 18:50

Hallo Marco

Ich nehme an, du verwendest eine CH-DB. Da müsste es die Codeunit 11501 GeneralMgt geben mit CH-Erweiterungen für Ansi2Ascii und Ascii2Ansi.

Diese CU sollten mit jeder Lizenz verwendbar sein.

11. Oktober 2006 19:48

*grins* Stimmt, die Codeunit gibt es natürlich auch noch und die darin enthaltene ASCII2ANSI-Funktion ist absolut identisch mit meinem ersten Entwurf (aus einer Branchenlösung), wo ich noch mit einer Schleife den Text konvertierte.
Aufgrund der Performance-Probleme hatte ich die Funktion dann auf CONVERTSTR umgestellt.

So ist das, wenn man Branchenlösungen programmiert.
Der Partnervertrag erlaubt es nunmal, dass Entwicklungen der Partner in den Standard übernommen werden

Wenigstens haben sie meine alte Version übernommen, so hat meine Funktion immer noch eine Daseins-Berechtigung ;-)

12. Oktober 2006 08:26

Guten Morgen

wow, schon so viele Antworten. Danke dass ihr euch Zeit genommen habt. Habe gerade Sitzung, werde eure Vorschläge erst später testen können.

Ich denke mit Kowa's Beispiel werde sogar ich das hinbringen...

Timo Lässer's Vorschlag werde ich auch mal probieren. Soweit hab ich gar nicht überlegt. Hab zwar nicht die Rechte, bei den Codeunits etwas zu ändern (Kostet 7000.-), aber eine Codeunit mit Nummer 50000 könnte ich Theoretisch importieren... (Fehler des Distributors). Mal probieren...


Dann noch zu rotsch: Eeehrm, ich sag jetzt einfach mal ja :-)
Jap, diese Codeunit gibts. Leider kann ich weder editen, noch passiert bei run etwas...

So, muss an die Sitzung. Melde mich noch, obs geklappt hat. Vielen Dank

12. Oktober 2006 08:35

Die Codeunit 11501 enthält zwei Funktionen

Code:
Ansi2Ascii(_String : Text[250]) _Output : Text[250]
Ascii2Ansi(_String : Text[1024]) : Text[1024]


Du kannst diese Codeunit in jedem anderen Programm als Variable deklarieren und die Funktionen daraus ansprechen. Mit Run passiert nicht nichts, da kein Code im OnRun-Trigger hinterlegt ist.

12. Oktober 2006 10:41

Ach, programmieren ist nicht mein ding :cry:

Zu Timo Lässer: Funktioniert leider nicht. Kann mit meiner Lizenz keine Codeunits importieren... Kann auch keine neue erstellen über Button new, nur wenn ich ganz nach unten scrolle und direkt im Object Designer eintrage gehts. Bearbeiten kann ich dann aber auch nicht.

Kowa: Bei deinem Beispiel kommt immer, := kann nicht auf Arrays ausgeführt werden. Hab aber noch nicht gross herumprobiert

Rotsch: Ich habe es jetzt mal nach deinem Beispiel versucht umzusetzen. Mit Betonung auf versucht :-|

- Eine Variable mit dem Namen convert erstellt, welche auf die codeunit verweist (11501).
- Eine Variable namens text (Typ:Text)
- Eine Variable namens datei (Typ: File)

Code (OnPostDataItem):

Code:
convert.Ascii2Ansi(text);
datei.CREATE('C:\test2.txt');
datei.WRITE(text)


Jetzt müsste doch theoretisch der konvertierte Text in die Variable "Text geschrieben werden, oder?
Die Datei bleibt aber leider leer... Weiss jemand, worans liegen könnte?
Die vom Dataport erstellte Datei hätte auch mehr als 250Zeichen, wenn ich keine Filter setzten würde. Das würde dann so nicht gehen, oder?
Kann mans auch direkt in die vom Dataport erstellte Datei reinschreiben? So wird ja eine zweite erstellt...

Wäre nett, wenn jemand helfen könnte...

Edit: Wenn ich den Code bei "onbeforeexport" Trigger einfüge, gehts viel länger. Er macht also schon irgendwas... Nur ist die beim Dataport angegebene Datei immernoch falsch was äöü angeht, und die 'C:\test2.txt' immernoch leer...

12. Oktober 2006 10:57

Marco hat geschrieben:Ach, programmieren ist nicht mein ding :cry:

Kopf hoch, nach 10 Jahren kannst du das im Schlaf :wink:


Marco hat geschrieben:Jetzt müsste doch theoretisch der konvertierte Text in die Variable "Text geschrieben werden, oder?
Die Datei bleibt aber leider leer... Weiss jemand, worans liegen könnte?


Der Code muss so aussehen:
Code:
KonvertierterText := convert.Ascii2Ansi(text);


Die Funktion hat einen Rückgabeparameter, der den konvertierten Text zurückgibt, den du mit der Variablen text an die Funktion übergibst.

12. Oktober 2006 11:33

Marco hat geschrieben:Kowa: Bei deinem Beispiel kommt immer, := kann nicht auf Arrays ausgeführt werden. Hab aber noch nicht gross herumprobiert

Zielwert ist hier eine normale Textvariable ohne Dimensionen. Die Arraydarstellung ist hier nur dazu da, die einzelnen Elemente innerhalb der Variable direkt anzusprechen.

12. Oktober 2006 12:21

Leider habe ich es in angemessener Zeit nicht fertiggebracht, weshalb wir das im Geschäft jetzt halt mit einem Zwischenschritt in UltraEdit konvertieren. Wenn ich mehr Zeit habe versuche ich mich nochmals daran und werde ev. nochmals hier fragen. Aber nochmals einen Tag an diesem Problem verbringen kann ich nicht ...

Ich müsste vielleicht mal einen C/AL Kurs besuchen...

Vielen Dank an Kowa, rotsch und Timo für eure Hilfe! Habe noch kein Forum vergeichbarer Qualität im Computerbereich gefunden. Normalerweise drehen sich 50% der Antworten um was anderes oder sind dumme Bemerkungen über Rechtschreibfehler.

Gruess Marco

12. Oktober 2006 12:47

Ich habe hier mal einen kleinen Dataport ID 50090 für Artikelexport ( Nr. , Beschreibung,Beschreibung 2) mit Trennzeichen ;, wo diese Funktion drin ist. Diese wird dort direkt in der SourceExpr der Dataportfields angewendet. Vielleicht hilft dir das ja weiter.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Zuletzt geändert von Kowa am 12. Oktober 2006 12:57, insgesamt 2-mal geändert.

12. Oktober 2006 12:53

Marco hat geschrieben:Vielen Dank an Kowa, rotsch und Timo für eure Hilfe! Habe noch kein Forum vergeichbarer Qualität im Computerbereich gefunden. Normalerweise drehen sich 50% der Antworten um was anderes oder sind dumme Bemerkungen über Rechtschreibfehler.

Danke für die Blumen :-D
Das ist auch mit ein Grund, weshalb ich mich hier im Forum einsetze. Wir vom Team achten unter anderem auch darauf, dass ein sachlicher, freundlicher Umgangston herrscht hier. Das kommt allen zugute.

12. Oktober 2006 13:11

Wow, und ob mir das weiterhilft. Unglaublich, dieses Forum!
Also sowas hätte ich jetzt echt nicht erwartet.
Jetzt laufts tiptop... Bin sprachlos :-D
VielenVielen Dank
Edit: Aah, jetzt sehe ich was ich falsch gemacht habe. Statt beim Register "Return Value" die Felder auszufüllen, habe ich eine Variable Rückgabewert erstellt (war bis heute noch gar nie im Locals-Menü..).
Beim nächsten mal weiss ich, was mit Rückgabewert gemeint ist :wink:

12. Oktober 2006 13:27

Du kannst selber bestimmen, ob du für den Rückgabewert einen Namen eintragen, oder nur den Typ des Rückgabewertes angeben willst. Je nach dem ändert sich das Verhalten.

Ohne Namen musst für die Rückgabe den Befehl EXIT verwenden. In die Klammer kommt der Wert, den du zurückgeben willst
Code:
EXIT();


Wenn du mit einem Namen für den Rückgabewert arbeitest hast du automatisch eine lokale Variable mit diesem Namen. Dieser kannst du einen Wert zuweisen, der dann zurückgegeben wird. EXIT ist dann nicht mehr nötig (ausser du willst an einer bestimmten Stelle aus irgendeinem Grund aus der Funktion springen)

12. Oktober 2006 18:34

Marco hat geschrieben:[...]
Vielen Dank an Kowa, rotsch und Timo für eure Hilfe! Habe noch kein Forum vergeichbarer Qualität im Computerbereich gefunden. Normalerweise drehen sich 50% der Antworten um was anderes oder sind dumme Bemerkungen über Rechtschreibfehler.

Gruess Marco
Solche Foren kenne ich leider auch zugenüge und bin wirklich froh, dass hier ein so guter Zusammenhalt herrscht, wo jeder gerne dem Anderen hilft bzw. sich enthält, falls er/sie keinen Tipp beisteuern kann.
Auch der Ehrgeiz, mit dem hier versucht wird, anderen zu helfen, ist wirklich erstaunlich. Hier wird solange geholfen, bis es endlich funktioniert.

An dieser Stelle danke ich dir ebenfalls für dein großes Lob und reiche es auch mal gleich an alle Benutzer dieser Community weiter, da wir vom Team sowas niemals ohne die aktive Mithilfe aller bewerkstelligen könnten.

Hilfe!

6. Februar 2007 14:16

rotsch hat geschrieben:Ich nehme an, du verwendest eine CH-DB. Da müsste es die Codeunit 11501 GeneralMgt geben mit CH-Erweiterungen für Ansi2Ascii und Ascii2Ansi.

Ich brauche dieses Codeunit ganz dringend für die deutsche 3.70-Version.
Finde auf der Kundendatenbank aber weder die Nummer noch den Namen.
Danke!

6. Februar 2007 14:56

Hallo Natalie,

ich habe den Beitrag nur überflogen!
Du kannst dir diese CU recht einfach selbst erstellen.
Erstelle 2 Funktionen "NavisionToWord" und "WordToNavision", je nachdem wie du mit diesen Arbeiten möchtest, gebe denen einen Parameter vom Typ Text und ein Return Type Text.
Den Code in die jeweilige Funktion kopieren
[code]
// Funktion NavisionToWord
CONVERTSTR(Text,'ßäöüÄÖÜéè','
Zuletzt geändert von mikka am 6. Februar 2007 17:13, insgesamt 1-mal geändert.

6. Februar 2007 15:16

Danke!

Das heißt, in der deutschen 3.70 gibts eine solche fertige Codeunit überhaupt nicht?

6. Februar 2007 15:19

Falls du die Copy/Paste-Methode vorziehst, hier die beiden Funktionen:

Code:
Ansi2Ascii(_String : Text[250]) _Output : Text[250]
// Converts from ANSI to ASCII

FOR i := 1 TO STRLEN(_String) DO BEGIN

  Z := _String[i];

  CASE Z OF
    // Convert special chars in ASCII
    228: Z := 132; // ä   ANSI=Alt0228, ASCII=Alt132
    196: Z := 142; // Ä
    226: Z := 131; // â
    224: Z := 133; // à
    225: Z := 160; // á
    229: Z := 134; // å
    197: Z := 143; // Å
    230: Z := 145; // æ
    198: Z := 146; // Æ

    199: Z := 128; // Ç
    231: Z := 135; // ç

    233: Z := 130; // é
    234: Z := 136; // ê
    235: Z := 137; // ë
    232: Z := 138; // è
    201: Z := 144; // É

    239: Z := 139; // ï
    238: Z := 140; // î
    236: Z := 141; // ì
    237: Z := 161; // í

    246: Z := 148; // ö
    214: Z := 153; // Ö
    244: Z := 147; // ô
    242: Z := 149; // ò
    243: Z := 162; // ó

    252: Z := 129; // ü
    220: Z := 154; // Ü
    251: Z := 150; // û
    249: Z := 151; // ù
    250: Z := 163; // ú

    241: Z := 164; // ñ
    165: Z := 209; // Ñ
    255: Z := 152; // ÿ
    163: Z := 156; // £
    248: Z := 157; // ø
  END;

  _String[i] := Z;
END;

EXIT(_String);



Code:
Ascii2Ansi(_String : Text[1024]) : Text[1024]
// Converts from ASCII to ANSI

FOR i := 1 TO STRLEN(_String) DO BEGIN

  Z := _String[i];

  CASE Z OF

    // Convert special chars in ANSI
    132: Z := 228; // ä  ASCII=Alt132, ANSI = Alt0228
    142: Z := 196; // Ä
    131: Z := 226; // â
    133: Z := 224; // à
    160: Z := 225; // á
    134: Z := 229; // å
    143: Z := 197; // Å
    145: Z := 230; // æ
    146: Z := 198; // Æ

    128: Z := 199; // Ç
    135: Z := 231; // ç

    130: Z := 233; // é
    136: Z := 234; // ê
    137: Z := 235; // ë
    138: Z := 232; // è
    144: Z := 201; // É

    139: Z := 239; // ï
    140: Z := 238; // î
    141: Z := 236; // ì
    161: Z := 237; // í

    148: Z := 246; // ö
    153: Z := 214; // Ö
    147: Z := 244; // ô
    149: Z := 242; // ò
    162: Z := 243; // ó

    129: Z := 252; // ü
    154: Z := 220; // Ü
    150: Z := 251; // û
    151: Z := 249; // ù
    163: Z := 250; // ú

    164: Z := 241; // ñ
    165: Z := 209; // Ñ
    152: Z := 255; // ÿ
    156: Z := 163; // £
    157: Z := 248; // ø
  END;

    _String[i] := Z;
END;

EXIT(_String);

6. Februar 2007 15:26

Watt fürn Service - hartelijk bedankt!

6. Februar 2007 15:48

Du hast doch gesagt, dass du das sehr dringend brauchst :-D

6. Februar 2007 16:32

Stimmt ja auch :-)

6. Februar 2007 16:49

Bei der CH-Version fehlt aber ( wie zu erwarten :-) ) das "ß".

6. Februar 2007 17:22

Wie gut, dass ich ohnehin mikkas Version benutzt hatte 8-)