OpenOffice dokumentumból szöveg kinyerése

Ismét .NET

Most éppen megnyitott OpenOffice dokumentumból kell kiszedni a szöveget. A letöltött OpenOffice SDK-ból kell betenni a References-be az öt darab cli_*.dll -t. Aztán:


public class OpenOfficeReceiver : ITextReceiverInterface.ITextReceiver
{

private XTextDocument oDoc;

public void createDocument()
{
XComponentContext oStrap = uno.util.Bootstrap.bootstrap();
XMultiServiceFactory oServMan = (XMultiServiceFactory)oStrap.getServiceManager();
XComponentLoader oDesk = (XComponentLoader)oServMan.createInstance("com.sun.star.frame.Desktop");
string url = @"private:factory/swriter";
PropertyValue[] propVals = new PropertyValue[0];
oDoc = (XTextDocument)oDesk.loadComponentFromURL(url, "_blank", 0, propVals);
}

public String giveBackTheTextContent()
{
return oDoc.getText().getString();
}
}
Már megint egy bejegyzés, ami .NET-es és nem Java-s. Az alábbi kód a "Word" title-lel rendelkező alkalmazáson figyeli az Enter gomb lenyomását.


public class FilterLogic{

public delegate void filteredEvent();

private filteredEvent currentFilteredEvent;
private InfoDelegate infoDelegate;
private Logger logger;

public FilterLogic(InfoDelegate infoDelegate)
{
this.infoDelegate = infoDelegate;
this.logger = new Logger(infoDelegate, "FilterLogic");
}

public void setFilteredEvent(filteredEvent currentFilteredEvent){
this.currentFilteredEvent = currentFilteredEvent;

}



public void filterEnterAndApp(IntPtr a, ref Hook.KBDLLHOOKSTRUCT lParam)
{

//ENTER KEY
if (0X0D == lParam.vkCode)
{

try
{

IntPtr hwnd = APIFuncs.getforegroundWindow();
Int32 pid = APIFuncs.GetWindowProcessID(hwnd);
Process p = Process.GetProcessById(pid);
String appName = p.ProcessName;
String appltitle = APIFuncs.ActiveApplTitle().Trim().Replace("\0", "");
Console.WriteLine(appltitle);
if (appltitle != null && appltitle.Contains("Word"))
{
if (currentFilteredEvent != null)
{

currentFilteredEvent();

}
else
{
logger.logMsg(Logger.WARNINGTYPE, "there is no filteredEvent is set, so no function will be called.");

}
}

}
catch (Exception ex)
{
logger.logException(ex);
}
}
}
}


public static class Hook
{
//Similar class is on this site:
//http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx

private static class API
{

//dll imports for hooking and unhooking and sending events trough hook hierarchy

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(
int idHook,
HookDel lpfn,
IntPtr hMod,
uint dwThreadId);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(
IntPtr hhk);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(
IntPtr hhk,
int nCode,
IntPtr
wParam,
//IntPtr lParam);
ref KBDLLHOOKSTRUCT lParam);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(
string lpModuleName);

}

public struct KBDLLHOOKSTRUCT
{
public int vkCode;
int scanCode;
public int flags;
int time;
int dwExtraInfo;
}

public delegate IntPtr HookDel(
int nCode,
IntPtr wParam,
ref KBDLLHOOKSTRUCT lParam);

public delegate void KeyHandler(
IntPtr wParam,
ref KBDLLHOOKSTRUCT lParam);

private static IntPtr hhk = IntPtr.Zero;
private static HookDel hd;
private static KeyHandler kh;

//Creation of the hook
public static void CreateHook(KeyHandler _kh)
{
Console.WriteLine("CreateHook _kh: " + _kh);
Process _this = Process.GetCurrentProcess();
ProcessModule mod = _this.MainModule;
hd = HookFunc;
kh = _kh;

hhk = API.SetWindowsHookEx(13, hd, API.GetModuleHandle(mod.ModuleName), 0);
//13 is the parameter specifying that we're gonna do a low-level keyboard hook
//Console.WriteLine(Marshal.GetLastWin32Error().ToString());
//MessageBox.Show(Marshal.GetLastWin32Error().ToString()); //for debugging
//Note that this could be a Console.WriteLine(), as well. I just happened
//to be debugging this in a Windows Application
}

public static bool DestroyHook()
{
//to be called when we're done with the hook

return API.UnhookWindowsHookEx(hhk);
}

//called when key is active
private static IntPtr HookFunc(
int nCode,
IntPtr wParam,
ref KBDLLHOOKSTRUCT lParam)
{
//Console.WriteLine("nCode=" + nCode);
//Console.WriteLine("wParam=" + wParam);

int iwParam = wParam.ToInt32();
//depending on what you want to detect you can either detect keypressed or keyrealased also with a bit tweaking keyclicked.
if (nCode >= 0 && (iwParam == 0x100 ||
iwParam == 0x104)) //0x100 = WM_KEYDOWN, 0x104 = WM_SYSKEYDOWN
kh(wParam, ref lParam);

return API.CallNextHookEx(hhk, nCode, wParam, ref lParam);
}
}



class APIFuncs
{

#region Windows API Functions Declarations

//This Function is used to get Active Window Title...
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetWindowText(IntPtr hwnd, string lpString, int cch);

//This Function is used to get Handle for Active Window...
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern IntPtr GetForegroundWindow();

//This Function is used to get Active process ID...
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out Int32 lpdwProcessId);

#endregion

#region User-defined Functions

public static Int32 GetWindowProcessID(IntPtr hwnd)
{
//This Function is used to get Active process ID...
Int32 pid;
GetWindowThreadProcessId(hwnd, out pid);
return pid;
}

public static IntPtr getforegroundWindow()
{
//This method is used to get Handle for Active Window using GetForegroundWindow() method present in user32.dll
return GetForegroundWindow();
}

public static string ActiveApplTitle()
{
//This method is used to get active application's title using GetWindowText() method present in user32.dll
IntPtr hwnd = getforegroundWindow();
if (hwnd.Equals(IntPtr.Zero)) return "";
string lpText = new string((char)0, 100);
int intLength = GetWindowText(hwnd, lpText, lpText.Length);
if ((intLength <= 0) || (intLength > lpText.Length)) return "unknown";
return lpText.Trim();
}

#endregion
}

A loggertől és az infoDelegate-től tekintsünk el, mindkettő csak a logolást segítette. Beregisztrálni és leregisztrálni a keylistenert a kódban, ahol ezt meg akarjuk tenni, a következőképp lehet:


Hook.CreateHook(new Hook.KeyHandler(filterLogic.filterEnterAndApp));


Hook.DestroyHook();
Javabuzi meghasonulva

Bár javabuzi vagyok, vannak olyan feladatok, amikre nem a Java a legalkalmasabb. Mostanság több ilyen is adódott, kellett használni flex-et, grails-t, .NET-et is.

Tehát a probléma: szedjük ki bizonyos időközönként egy aktuálisan megnyitott dokumentumból a szöveget. C#.NET-et találtam a legkényelmesebbnek ehhez, bár így sem volt egyszerű. Rengeteg írás van a neten, hogy hogyan bizergáljunk lementett doc fájlokat, de ritka, hogy hogyan dolgozzunk egy aktuálisan megnyitott doksival. Annyi könnyíti a helyzetemet, hogy magát a dokumentumot az elején feldobhatom én is, így nem kell kikeresnem az aktívot, hanem feltételezhetem, hogy az általam megnyitottba írnak majd. Csupán a Microsoft.Office.Core és a Microsoft.Office.Interop.Word dll-eket kell csak behúzni. A kód valami ilyesmi, persze még az ütemes giveBackTheText() hívások kellenek köré:

public class WordTextReceiver
{

private Microsoft.Office.Interop.Word.Application wordApp;
private Document doc;


public void init()
{
createWordDocument();
}

private void createWordDocument()
{
wordApp = new Microsoft.Office.Interop.Word.Application();

object readOnly = false;
object isVisible = true;

// Here is the way to handle parameters you don't care about in .NET
object missing = System.Reflection.Missing.Value;
wordApp.Visible = true;

try
{
doc = wordApp.Documents.Add(ref missing, ref missing, ref missing, ref isVisible);

}
catch (COMException ce)
{
// some logging or error handling here
}

doc.Activate();
}


public String giveBackTheText()
{
return doc.Content.Text;
}
}
Szintakszis szinezés (vagy kiemelés?)

Nem igazán értettem eddig, hogy milyen problémás dolog tud lenni egy kódot szépen csicsázva publikálni egy blogon. Ez tipikusan olyasvalami, mely felett átsiklik az ember, elintézi annyival magában, hogy ODA KELL KOPIPÉSZTELNI, OSZT KÉSZENVAN. De ha egy kicsit is eltűnődsz, nem is oly egyszerű. Lehetőség lenne, hogy magadnál átfuttasd a kódodat egy html+css csicsázó készüléken, és az outputot kopizod a blogbejegyzésedbe. Ez nehezen módosítható utólag, béna megoldás.


Az ultimate megoldást egy sörivó srác adja (azért kér donation-t, hogy sört vehessen), itten van az oldala: http://alexgorbatchev.com/wiki/SyntaxHighlighter. Itt meg egy srác blogja, aki leírja, hogy ezt hogy is kell használni bloggeren: http://blog.cartercole.com/2009/10/awesome-syntax-highlighting-made-easy.html.


Röviden annyi a trükk, hogy javascript+css kombóval csinálja a syntax highlight-ot, magyarul runtime az oldal betöltésekor csicsáz, így a forrásban szépen módosítható marad a kód, cserélhető a stílus. A javascript kód ingyenes hosztolása is megoldott (mivel ugye bloggerre nemnagyon tehetsz fel ilyet).



Itt egy példa a script-es beillesztésre:




Itt meg egy a pre-s beillesztésre:



public class Allat{
private String str = "";
}


Különbséget nem látok, az indentálás mindkettőnél megmaradt, mindenesetre a pre-s rövidebb. Ja, és valami swf-es trükkel megcsinálták a kopipésztelhetőséget is, bár én nyomát sem találom flashnek, pedig SZÉTJOBBKLIKKELTEM az egész kódrészt... Szórszkódba meg nincs kedvem belenézni, működik és kész, ez az, amit szeretek.

UPDATE: mégis megtaláltam a flasht... nem eléggé SZÉTJOBBKLIKKELTEM előbb.

Licensz választás

Őrjítő dolog (angol) jogi szöveget olvasni egy programozónak.

És hihetetlen, hogy nem találtam normális for dummies stílusú leírást sem. Pedig most rákényszerültem, hogy körbenézzek ebben a témában. Akarok/akarunk indítani egy opensource projektet, nem akarom korlátozni a felhasználóit, hogy arra használják, amire csak akarják... ingyen, és anélkül, hogy nekik openszórsszá kelljen tenniük a fejlesztéseiket (nem teljesen szívjóságból, hiszen a projektet majd mi is természetesen üzleti célokra szeretnénk felhasználni, márpedig a kiegészülő részek openszórsszá tétele nélkül). Másik oldalról persze már szeretnénk mi is több kész komponenst is használni, tehát ezekkel is kompatibilis kell legyen a kiválasztott licensz. A szituáció adott, a választék is adott, van GPL (mindenféle verzióban), van LGPL (v3), BSD, CC.
Először azt hittem, hogy a http://www.gnu.hu segítséget nyújt, hisz legalább magyar. Tévedtem. Ez nem magyar, hanem egy senki által nem beszélt nyelv. Inkább visszatértem az angol leírásokra. Két értelmesebb oldalt találtam csak. Az egyik a Java viszonylatában magyarázza el az LGPL v2.1 -et, ami nyilván nagyon hasonlít a v3-ra: http://www.gnu.org/licenses/lgpl-java.html. Másik az egy magyar fórumbeszélgetés a CC és az LGPL közti különbségekről, megvilágítva az LGPL egyes elemeit: http://weblabor.hu/forumok/temak/19865.
A maradék licenszeket az eredeti angol leírásból próbáltam megértegetni, de már az elején sejtettem, hogy a GPL túl szigorú a felhasználást illetően, a BSD viszont túl engedékeny, hogy én ügyesen felhasználgathassak erősebb megkötésű komponenseket.
Marad az LGPLv3, míg jobbat nem találunk ki... Feladat kipipálva.
top