fastxml 大于符号不转换_利用 Notepad++ 插件技术开发直接打开 FastInfoset 格式 XML 文件...

本文介绍了如何利用Notepad++的插件技术开发直接打开和保存FastInfoset格式的XML文件。FastInfoset是一种优化的XML序列化技术,能提高效率和减少文件大小。作者详细讲解了FastInfoset的处理方法,包括使用Java API进行打开和保存,并展示了如何通过JNI在C++和Java之间进行交互,以实现在Notepad++中支持FastInfoset文档。
摘要由CSDN通过智能技术生成

利用 Notepad++ 插件技术开发直接打开 FastInfoset 格式 XML 文件

骆毅

2012 年 9 月 03 日发布

简述

FastInfoset定制了一种在二进制级别处理 XML 信息集合的方式,通过这种特殊的序列化,与普通的 XML 文档相比,无论在大小和解析速度上都有特殊的优势。

Notepad++是一款优秀的文本编辑软件,开源、免费和多种插件支持使得它成为最流行的编辑软件之一,其中强大的插件功能可以让 Notepad++ 对各种文本文件良好的支持,如下图所示 :

图 1. Notepad++ 展示 XML

对 XML 而言,优秀的处理能力体现在标签着色和树形折叠,但是 Notepad++不能直接打开 FastInfoset 文档,本文就是已解决这个问题为目的,利用 Notepad++的插件技术,来直接打开和保存 FastInfoset文档。包括以下几个问题:打开、存储 FastInfoset 的库由 Java 提供,必须建立 JNI 的调用结构来管理代码;

插件的开发模型,包括重点使用的函数,调用的流程和开发代码;

JNI 调用。

FastInfoset 文件处理

FastInfoset 技术简述

FastInfoset利用现实当中 XML 文件当中大量存在的重复信息的特点,比如前面提到的 books.xml,可以看到大量重复的标签,然后利用这种各种处理字符的技术,压缩 XML 文件和提高访问速度。这些技术包括动态表、原始词集合和外部词汇表等等。

打开和保存 FastInfoset

来自 GlassFish 的技术中的一部分,用户可以访问 http://fi.java.net 来获得 Fast Infoset的技术支持,由于 Java 的技术,FastInfoset 的接口都是使用 Java 编写,其中的部分代码如下所示:打开 FastInfoset 文档

清单 1. 打开 FastInfoset文档DefaultContentHandler builder = new DefaultContentHandler();

// Instantiate the FI SAX parser

XMLReader saxReader = new SAXDocumentParser();

saxReader.setContentHandler(builder);

// Parse the fast infoset document

InputSource inputSource = new InputSource(stream);

saxReader.parse(inputSource);

保存 FastInfoset 文档

清单 2. 保存 FastInfoset文档final java.io.StringReader reader = new java.io.StringReader(saveString);

// Get the input stream for the XML document

InputStream xmlDocument = new InputStream(){

@Override

public int read() throws IOException {

// TODO Auto-generated method stub

return reader.read();

}

};

// Set up output stream for fast infoset document

OutputStream fiDocument = new FileOutputStream(new File(filePath));

// Create Fast Infoset SAX serializer

SAXDocumentSerializer saxDocumentSerializer = new SAXDocumentSerializer();

// Set the output stream

saxDocumentSerializer.setOutputStream(fiDocument);

// Instantiate JAXP SAX parser factory

SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();

/* Set parser to be namespace aware

* Very important to do otherwise invalid FI documents will be

* created by the SAXDocumentSerializer

*/

saxParserFactory.setNamespaceAware(true);

// Instantiate the JAXP SAX parser

SAXParser saxParser = saxParserFactory.newSAXParser();

// Set the lexical handler

saxParser.setProperty("http://xml.org/sax/properties/lexical-handler",

new FastInfosetDefaultHandler());

// Parse the XML document and convert to a fast infoset document

saxParser.parse(xmlDocument, saxDocumentSerializer);

Notepad++ 插件技术

Notepad++ 的插件简单结构

Notepad++的核心是 Scintilla 的跨平台编辑控件,由 C++ 编写,使用纯 Win32 接口和 STL。所以一个典型的 Notepad++ 插件需要由 C++ 编写,核心是控制 Scintilla 控件的行为。为此,整个代码的结构分为以下几个部分。Java 部分,包括开放的接口和对 FastInfoset XML 文档的支持;

插件部分,开发包括控制 Notepad++ 中 Scintilla 控件文本的显示,以及通过 JNI 接口构建 Java 虚机调用 Java 接口的方法。

Notepad++插件的开发提供了一套标准的流程,提供了操作菜单的消息,操作 Scintilla 控件的消息,还有插件的入口,资源回收的终结等等。开发起来只需要提供自己的类型,让它工作在合适的位置即可。

Notepad++ 插件开发要旨

Notepad++ 开发的要点主要分布在以下几个接口中,描述如下:插件的名称和自我描述,这一部分定义了插件在 plugin 菜单的显示,包括入口名称和子菜单条目。一般来说入口的名称显示在菜单向上,Notepad++ 定义了一个全局变量 NPP_PLUGIN_NAME 来描述这个名称,我们只需要更改它即可。

图 2 菜单项目和子菜单

插件的运行核心。所有的插件依赖 UI 的 plugin 菜单来激发一个特定的任务,所有的菜单初始化选项必须在 commandMenuInit 函数中完成。利用 Notepad++暴露的方法 setCommand 方法,可以把菜单项与插件自定的方法体关联起来,setCommand 的方法定义如下:

清单 3. setCommand 定义bool setCommand(size_t index,

TCHAR *cmdName,

PFUNCPLUGINCMD pFunc,

ShortcutKey *sk = NULL,

bool check0nInit = false);

其中的参数意义如下 :index:从零开始,表示菜单项目的顺序;

commandName: 显示在菜单上的名称;

functionPointer: 函数指针,表示函数的确切地址;

shortcut: 可选择,快捷键定义;

check0nInit: 可选择,定义这个菜单项是否为默认已选择条目。

如图 2 所示,利用 setCommand 函数所设置的相会自动显示在已定义的插件菜单条目中。

与 Notepad++的交互。在自定义的函数体内,可以获取 Notepad++的句柄,用来设置一些全局的条目,利用模板中定义好的导出函数 setInfo,Notepad++ 程序就会给插件提供一个 NppData 结构实例,其中就有当前 Notepad++的句柄。在本文中所示的插件视线中,打开 FastInfoset文件后,为了显示 XML 着色,必须发送一条切换语言的消息如下:

清单 4. 发送消息到 Notepad++::SendMessage(nppData._nppHandle,NPPM_SETCURRENTLANGTYPE,

0,(LPARAM)LangType::L_XML);

这样就可以在打开 FastInfoset 文件立刻切换至 XML 语言。

更重要的,插件需要与 Scintilla 控件交互,为了获取 Scintilla 的句柄,需要对 Notepad++ 程序问询,使得 Notepad++ 能够返回当前需要的 Scintilla 句柄。有了 Scintilla 句柄 ,就可以通过多种消息来控制显示和获取当前的文本了。方式如下:

清单 5. 设置文本// 设置文本

::SendMessage(curScintilla, SCI_SETTEXT, 0, (LPARAM)str);

清单 6. 获取文本// 获取文本

::SendMessage(curScintilla, SCI_GETTEXT, (WPARAM)(Length+1), (LPARAM)str);

需要说明的是,文本的获取必须传递文本的大小和存储缓存,文本大小可以通过 SCI_GETLENGTH 消息来取得。

利用 JNI 沟通 C++ 与 Java

Java Native Interface(JNI)是 Java 语言的本地编程接口,是 J2SDK 的一部分。在 java 程序中,我们可以通过 JNI 实现一些用 java 语言不便实现的功能。通常有以下几种情况我们需要使用 JNI 来实现。标准的 java 类库没有提供你的应用程序所需要的功能,通常这些功能是平台相关的;

你希望使用一些已经有的类库或者应用程序,而他们并非用 java 语言编写的;

程序的某些部分对速度要求比较苛刻,你选择用汇编或者 c 语言来实现并在 java 语言中调用他们。

在 Notepad++中调用 Java 代码

为了使用 Java 代码来打开和保存 FastInfoset文档,必须做到以下几点:构建 Java 虚拟机,JVM 可以使用 JNI 暴露的 JNI_CreateJavaVM 方法来构建,最好的方法是提供 JVM 动态库的本地地址,使用系统提供的 LoadLibrary 方法加载,然后之间查找到“JNI_CreateJavaVM”方法的地址,调用之后来获取 JVM 和 JNIEnv。具体如下:

清单 7. 构造 JNI 的运行环境JavaVMInitArgs vm_args;

JavaVMOption options[3];

/* 设置初始化参数 */

// 设置 classpath,如果程序用到了第三方的 JAR 包,也可以在这里面包含进来

options[0].optionString=cp;

// 内存大小设置

options[1].optionString="-Xmx256m";

options[2].optionString="-Xms128m";

// 设置版本号,版本号有 JNI_VERSION_1_1,JNI_VERSION_1_2 和 JNI_VERSION_1_4

// 选择一个根你安装的 JRE 版本最近的版本号即可,不过你的 JRE 版本一定要等于或者高于指定的版本号

vm_args.version = JNI_VERSION_1_2;

vm_args.nOptions = 3;

vm_args.options = options;

vm_args.ignoreUnrecognized = JNI_TRUE;

// 加载 JVM.DLL 动态库

TCHAR JVM_LIB_HOME[MAX_PATH];

ZeroMemory(JVM_LIB_HOME,MAX_PATH*sizeof(TCHAR));

GetEnvironmentVariable(L"JVMDLL_HOME",JVM_LIB_HOME,MAX_PATH);

if(JVM_LIB_HOME[0] == '\0')

{

GetEnvironmentVariable(L"JAVA_HOME",JVM_LIB_HOME,MAX_PATH);

if(JVM_LIB_HOME[0] == '\0')

{

return;

}

}

TCHAR* FIX_JVM_LIB_PATH=L"\\jre\\bin\\server\\jvm.dll";

wcscat(JVM_LIB_HOME,FIX_JVM_LIB_PATH);

hInstance = ::LoadLibrary(JVM_LIB_HOME);

if(hInstance == NULL)

{

delete cp;

return;

}

// 取得里面的 JNI_CreateJavaVM 函数指针

PFunCreateJavaVM funCreateJavaVM = (PFunCreateJavaVM)::GetProcAddress(hInstance,

"JNI_CreateJavaVM");

// 调用 JNI_CreateJavaVM 创建虚拟机

jint res = (*funCreateJavaVM)(&jvm, (void**)&env, &vm_args);

构建的过程中,经常会因为各种问题失败,由于返回值仅仅是无符号数字,在 jni.h 的头文件中有有对应返回值的宏定义,有需要可以查询。比如文中提到的构建过程中遇到了返回值是 -4 的情况,查询后得知内存的大小未知,设置好需要的内存参数即可解决。

调用 Java 中的代码。利用创建好的 JVM 和 JNIEnv,就可以调用已有的 Java 代码,这些代码的库存在于穿件 JVM 时提供的 Classpath,首先必须查找到提供的类型,如下所示:

清单 8. 调用 Java 代码// 构造需要的类型实例

jclass cls = env->FindClass("plugin/xml/entryreader/internal/DocAchieve2");

// 然后查询所需要的函数:

jmethodID mid = env->GetMethodID(cls, "openFIDocument",

"(Ljava/lang/String;)Ljava/lang/String;");

// 最后调用函数即可:

jstring content = (jstring)env->CallObjectMethod(doc,mid,path);

在这里,env 的类型 JNIEnv,暴露了各种方法来构建 Java 实例和调用 Java 实例的方法,另外参数传递当中经常使用 Java String 类型和 C++ 中的 char 类型的转换,JNIEnv 也提供了完善的方法 GetStringUTFChars。

小结

虽然插件技术可以解决打开和保存 FastInfosetXML 文档的问题,但是使用上还是不方便。如果未来可以拦截打开文件的消息,然后判断是否需要插件介入,就可以自动完成打开的工作,未来的工作方式就可以跟优秀。

相关主题参考

"Notepad++"主站 首页,查看 Notepad++ 插件开发技术的详细信息。

参考“Java JNI Technology”,了解更多如何使用 JNI 技术的细节。

在 developerWorks 中国网站 XML 专区 进一步了解 XML 技术及其标准。查找技术文档、how-to 文章、培训等。

现在您可以免费使用 DB2。下载 IBM 软件下载:IBM DB2 Express-C 10.1,这是 DB2 Express Edition 的一个面向社区的免费版本,提供了与 DB2 Express Edition 相同的核心数据功能,为构建和部署应用程序提供了牢固的基础。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值