
com.sta.cts.Parser Maven / Gradle / Ivy
package com.sta.cts;
import java.util.Vector;
import java.io.IOException;
import com.wutka.dtd.DTD;
import com.wutka.dtd.DTDAny;
import com.wutka.dtd.DTDItem;
import com.wutka.dtd.DTDName;
import com.wutka.dtd.DTDEmpty;
import com.wutka.dtd.DTDMixed;
import com.wutka.dtd.DTDChoice;
import com.wutka.dtd.DTDPCData;
import com.wutka.dtd.DTDElement;
import com.wutka.dtd.DTDCardinal;
import com.wutka.dtd.DTDSequence;
import com.sta.mlogger.MLogger;
/**
* Name: Parser
* Description:
* Die Klasse Parser ist die zentrale Klasse im Demo-Converter.
*
* Copyright: Copyright (c) 2001-2004, 2014, 2016-2019, 2021
* Company: >StA-Soft<
* @author StA
* @version 1.0
*/
public class Parser
{
/**
* Der zu verwendende Scanner.
*/
private Scanner scanner;
/**
* Die aus dem DTD-File gelesene DTD-Struktur.
*/
private DTD dtd;
/**
* Der aktuelle XML-Generator.
*/
private XMLGenerator xg;
/**
* True, falls XDebug-Modus => mehr Infos.
*/
private boolean myXDebug;
/**
* Zur Instantiierung eines Parsers.
*/
public Parser()
{
}
/**
* Ausgabe von strg, falls myXDebug = true.
* @param strg der Text, der ausgegeben werden soll.
*/
void print(String strg)
{
if (myXDebug)
{
MLogger.deb(strg);
}
}
/**
* Ausgabe von b, falls myXDebug = true.
* @param b der Boolean-Wert, der ausgegeben werden soll.
*/
void print(boolean b)
{
if (myXDebug)
{
MLogger.deb("" + b);
}
}
/**
* Ausgabe von strg und CRLF, falls myXDebug = true.
* @param strg der Text, der ausgegeben werden soll.
*/
void println(String strg)
{
if (myXDebug)
{
MLogger.deb(strg);
}
}
/**
* Ausgabe von CRLF, falls myXDebug = true.
*/
void println()
{
if (myXDebug)
{
MLogger.deb("");
}
}
/**
* Basis-Parser-Routine f?r Elements/SubElements und Hierarchien.
* Diese Basis-Parser-Routine soll alle Elements/SubElements in einer "Zeile"
* einer EDIFACT-Nachricht (bzw. einer andere Datei, z. B. CSV) (Fall v != null)
* bzw. ?bergeordnete Hierarchie-Ebenen (Fall v == null) parsen.
* * Hier werden nur Tags erzeugt und keine Token gelesen. Die Tags f?r das
* zu verarbeitende Item selbst werden au?erhalb, also in der ?bergeordneten
* Routine/Rekursionsebene erzeugt.
* * Rekursivit?t ist m?glich, es wird jedoch (im Fall v != null) nur eine
* Rekursionsstufe ben?tigt. Aufgerufen werden entweder nur parseItems
* (Fall v != null) oder parseStructure und parseItems (Fall v == null).
* * Die H?ufigkeiten werden in parseItems schon beachtet (1?+*).
* * Das Ergebnis ist "true", falls alles (!) Ok war (auch die H?ufigkeiten).
* * Das Ergebnis ist "false", falls die Token nicht oder nicht richtig passen,
* die H?ufigkeiten nicht stimmen oder ein genereller Fehler aufgetreten ist.
* Die Idee:
* je nach Typ(i):
* DTDAny:
* DTDEmpty:
* DTDName:
* Suche in Hash-Table
* gefunden:
* 1, +: parseElement, mu? true liefern
* ?: parseElement, Ergebnis egal
* +, *: parseElement, bis Ergebnis false
* nicht gefunden:
* DTDChoice:
* DTDSequence:
* F?r alle: parseItem
* DTDMixed:
* DTDPCDATA:
* @param item ein DTDItem aus der DTD-Struktur
* @param v ein Token (Vector) oder null, falls ?bergeordnete Struktur
* @return true, falls Ok; false, falls Parse-Error
* @exception IOException falls Schreibfehler im XML-Generator
*/
boolean parseItem(DTDItem item, Object v) throws IOException
{
String msg;
boolean b = false;
if (v == null)
{
msg = " Element: ";
}
else
{
msg = " Item: ";
}
if (item == null)
{
return false;
}
if (item instanceof DTDAny)
{
// Hier ist egal, was in v an Pos. i steht, es ist immer Ok.
print(msg + "Any");
// wird zur Zeit nicht unterst?tzt
b = false;
}
else if (item instanceof DTDEmpty)
{
// Hier darf nichts im Vector stehen.
print(msg + "Empty");
// wird zur Zeit nicht unterst?tzt
b = false;
}
else if (item instanceof DTDName)
{
// Hier mu? in der Hash-Tabelle gesucht werden.
String name = ((DTDName) item).value;
print(name);
DTDElement e = (DTDElement) dtd.elements.get(name);
if (e != null)
{
if (v != null)
{
if (v instanceof Vector)
{
if (((Vector) v).size() > 0)
{
Object v1 = ((Vector) v).elementAt(0);
if (v1 != null)
{
xg.openTag(name);
b = parseItems(e.content, v1);
xg.closeTag(name);
if (b)
{
if (v1 instanceof Vector)
{
b = (((Vector) v1).size() == 0);
}
/*
else
{
// b = (((String) v1) == "");
}
*/
if (b)
{
((Vector) v).remove(0);
}
}
}
}
}
else
{
xg.openTag(name);
b = parseItems(e.content, v);
/*
if (b)
{
// b = (((String) v) == "");
}
*/
xg.closeTag(name);
}
}
else
{
// Pr?fe, ob wenigstens noch ein Token kommt, sonst braucht man
// wahrscheinlich auch das Tag nicht zu ?ffnen...
Object o = scanner.getToken();
scanner.ungetToken(o);
if (o != null)
{
xg.openTag(name);
b = parseStructure(e);
xg.closeTag(name);
}
}
}
/*
>>> alt >>>
xg.openTag(name);
if (v == null)
{
b = parseStructure(e);
}
else
{
b = parseItems(e.content, v);
}
xg.closeTag(name);
<<< alt <<<
*/
print(b);
print(" ");
}
else if (item instanceof DTDChoice)
{
print("(");
DTDItem[] items = ((DTDChoice) item).getItems();
b = false;
for (int i = 0; i < items.length; i++)
{
if (i > 0)
{
print("|");
}
if (!b)
{
b = parseItems(items[i], v);
}
}
print(")");
}
else if (item instanceof DTDSequence)
{
print("(");
DTDItem[] items = ((DTDSequence) item).getItems();
b = true;
for (int i = 0; i < items.length; i++)
{
if (i > 0)
{
print(",");
}
boolean b1 = parseItems(items[i], v);
b = b & b1;
}
print(")");
}
else if (item instanceof DTDMixed)
{
print("(");
DTDItem[] items = ((DTDMixed) item).getItems();
b = true;
for (int i = 0; i < items.length; i++)
{
if (i > 0)
{
print(",");
}
boolean b1 = parseItems(items[i], v);
b = b & b1;
}
print(")");
}
else if (item instanceof DTDPCData)
{
// Hier mu? das Element im Vector ein String sein
// (bzw. ein Vector mit einem (einzigen) String
b = false;
print("#PCDATA");
if (v != null)
{
print(".");
if (v instanceof Vector)
{
print("*");
if (((Vector) v).size() >= 1)
{
print(">=1");
Object s = ((Vector) v).elementAt(0);
if (s != null)
{
if (s instanceof String)
{
print(" [ " + s + " ] ");
xg.putContent((String) s);
b = true;
}
else
{
print(" no string ");
}
}
else
{
print(" null ");
}
((Vector) v).remove(0);
}
else
{
print(" no elements ");
}
}
else if (v instanceof String)
{
print(" [ " + v + " ] ");
xg.putContent((String) v);
// v = "";
b = true;
}
else
{
print(" type error. ");
}
}
else
{
print(" null ");
}
// print(" [ " + item. + " ] ");
}
return b;
}
/**
* Parser-Routine f?r H?ufigkeiten/Kardinalit?ten.
* Diese Parser-Routine realisiert die Problematik "H?ufigkeiten" (1?+*).
* * Angewendet werden kann sie sowohl f?r Hierarchie-Ebenen (Fall v == null) als auch Element-Ebene(n) (fall v != null).
* * Aufgerufen wird parseItem mit item und v.
* @param item ein DTDItem aus der DTD-Struktur
* @param v ein Token (Vector) oder null, falls ?bergeordnete Struktur
* @return true, falls Ok; false, falls Parse-Error
* @exception IOException falls Schreibfehler im XML-Generator
*/
boolean parseItems(DTDItem item, Object v) throws IOException
{
String msg;
boolean b;
if (v == null)
{
msg = "Elements: ";
}
else
{
msg = "Items: ";
}
b = false;
if (item.cardinal == DTDCardinal.NONE)
{
b = parseItem(item, v);
print(msg + "1");
}
else if (item.cardinal == DTDCardinal.OPTIONAL)
{
parseItem(item, v);
print(msg + "?");
b = true;
}
else if (item.cardinal == DTDCardinal.ONEMANY)
{
b = parseItem(item, v);
if (b)
{
while (b)
{
b = parseItem(item, v);
}
b = true;
}
print(msg + "+");
}
else if (item.cardinal == DTDCardinal.ZEROMANY)
{
while (parseItem(item, v))
{
b = true;
}
print(msg + "*");
b = true;
}
return b;
}
/**
* Diese Routine Parser-Routine pr?ft, ob das n?chste Token mit dem Namen des
* ?bergebenen Elements beginnt.
* * Falls ja, wird der Name aus dem Token entfernt und parseItems mit dem
* Inhalt des DTD-Elements und dem Rest-Token aufgerufen. Es soll also das
* Rest-Token verarbeitet werden.
* * Falls nein, wird das Token zur?ckgelegt und parseItems mit dem Inhalt des
* DTD-Elements und "null" als Rest-Token aufgerufen. Es soll also eine
* weitere generelle Hierarchiestufe verarbeitet werden.
* * Die begrenzenden Tags werden erzeugt.
* @param e ein DTD-Element aus der DTD-Struktur
* @return true, falls Ok; false, falls Parse-Error
* @exception IOException falls Schreibfehler im XML-Generator
*/
boolean parseStructure(DTDElement e) throws IOException
{
Object o;
Object o1;
boolean run;
boolean b;
if (e == null)
{
return false;
}
o = scanner.getToken();
// if (o == null)
// {
// return false;
// }
// Falls o ein Vector ist und
// mindestens 1 Element enth?lt und
// dieses nicht null sondern ein String und
// noch dazu = dem Namen des Elements ist,
run = false;
if (o instanceof Vector)
{
if (((Vector) o).size() > 0)
{
o1 = ((Vector) o).elementAt(0);
if (o1 != null)
{
if (o1 instanceof String)
{
if (o1.equals(e.name))
{
run = true;
}
}
}
}
}
// dann entferne das erste Element des Vectors und
// rufe parseItems mit diesem Rest-Vector auf,
// sonst lege den Vector zur?ck und
// rufe parseItems mit null auf.
// print(" [ <" + e.name + "> ] ");
if (run)
{
((Vector) o).remove(0);
b = parseItems(e.content, o);
}
else
{
scanner.ungetToken(o);
b = parseItems(e.content, null);
}
// print(" [ " + e.name + "> ] ");
return b;
}
/**
* Diese "oberste" Parser-Routine l?st einen Namen via Hash-Tabelle auf und
* ruft damit parseStructure auf.
* neu:
* zus?tzliche Parameter:
* * Pfad/Name der Zieldatei(en) [PathName]
* * Typ der Zieldatei(en) [FileType]
* Der (die) komplette(n) Dateiname(n) der Zieldatei(en) ergibt (ergeben) sich
* dann aus PathName + i + FileType, wobei i eine laufende Nummer ist (0..).
* Bei i = 0 kann i weggelassen werden.
* Notwendig ist dies, falls aus einer Quell-(EDIFACT-)Datei mehrere
* XML-Dateien erzeugt werden m?ssen.
* @param pDTD eine DTD-Struktur, die in der Regel aus einem DTD-File
* gelesen wurde.
* @param pRootName der Name des Root-Tags
* @param pScanner der zu verwendende Scanner
* @param pDstFilePath der Pfad (incl. Basis-Dateiname excl. Typ) der
* Ziel-Datei.
* @param pDstFileType der Typ (Extension) der Ziel-Datei(en)
* @return Anzahl der erzeugten (und g?ltigen) Zieldateien oder 0, falls
* ein Fehler aufgetreten ist und/oder keine Datei erzeugt wurde.
* @exception IOException falls Lesefehler im Scanner (Quelldatei) oder
* Schreibfehler im XML-Generator (Zieldatei)
*/
public int convert(DTD pDTD, String pRootName, Scanner pScanner,
String pDstFilePath, String pDstFileType) throws IOException
{
DTDElement e;
boolean b;
String aTmpName;
int i;
Object o;
dtd = pDTD;
scanner = pScanner;
MLogger.deb("Parser: convert...");
// long time = System.currentTimeMillis();
e = (DTDElement) dtd.elements.get(pRootName);
if (e == null)
{
MLogger.err("Parser: convert: Error: Can't get root element.");
return 0;
}
xg = new XMLGenerator();
i = 0;
do
{
if (i == 0)
{
aTmpName = "";
}
else
{
aTmpName = Integer.toString(i);
}
// XML-Generator initialisieren und damit XML-File erstellen
xg.createXML(pDstFilePath + aTmpName + "." + pDstFileType);
// Root-Tag ?ffnen
xg.openTag(pRootName);
// Struktur parsen
b = parseStructure(e);
println();
// Root-Tag schlie?en
xg.closeTag(pRootName);
// XML-File schlie?en
xg.closeXML();
if (b)
{
i++;
}
o = scanner.getToken();
scanner.ungetToken(o);
}
while ((o != null) & (b));
// time = System.currentTimeMillis() - time;
if (b)
{
MLogger.deb("Parser: convert: Ok.");
}
else
{
MLogger.err("Parser: convert: Error.");
}
return i;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy