xml应用程序下载_改善XML应用程序的性能,第3部分

xml应用程序下载

在本系列的前两部分中,我们介绍了如何提高XML应用程序的性能,以及有关如何最好地编写XML文档,重用解析器以及更好地利用常规的Xerces2和SAX和DOM API的一般技巧。 。 在这里,我们展示了如何通过使用Xerces本机接口(XNI)并配置特定于Xerces2的功能和属性来优化应用程序的性能。 我们还将说明如何使用Xerces2缓存架构。

要了解如何使用Xerces2获得更好的性能,您需要对Xerces2设计和XNI有一定的了解。 因此,在本文中,我们简要概述了XNI,解释了它与SAX的不同之处以及如何使用XNI加快应用程序的速度。 如果您想了解更多关于XNI,请阅读Apache Xerces2的XNI手册(见相关主题 )。

Xerces本机接口(XNI)

Xerces2的内部结构建立在Xerces本机接口(XNI)上XNI是一个类似于SAX的流媒体文档信息通信框架,用于构造通用解析器及其组件。 XNI在大约两年前被宣布为稳定的,并且预计将来不会发生重大变化。

从理论上讲,其他解析器可以实现XNI接口,但是Xerces2当前似乎是唯一的解析器。 因此,XNI仍然是Xerces2解析器中用于在不同组件之间传递数据的内部API框架。

Xerces2设计

在Xerces2中,SAX和DOM解析器均包含XNI 解析器配置 ,该配置定义了解析器的入口点,以设置特征和属性以及启动XML文档的解析。 典型的解析器配置由一组组件组成 。 这些组件中的某些组件可以链接在一起形成一个解析管道 ,其中每个组件都使用XNI的文档处理程序接口将信息传达给下一个组件。 SAX和DOM解析器连接到管道中的最后一个组件,并负责从接收到的XNI流生成它们各自的API(SAX事件和DOM树)。

Xerces2框架将解析管道中组件的配置与API生成代码分开。 这种分离允许同一个API生成解析器与不限数量的不同解析器配置一起使用,并且还允许同一个解析器配置由不同的API生成解析器重用。

性能和解析器配置

您选择的解析器配置可能会影响应用程序的性能。 默认的解析器配置(从Xerces 2.6.2开始)支持XML 1.0 / 1.1,XML 1.0 / 1.1中的命名空间以及DTD和W3C XML Schema验证。 如果您的应用程序不需要验证,则可以通过使用非验证解析器配置( org.apache.xerces.parsers.NonValidatingConfiguration )获得更好的性能。

您可以覆盖Xerces2解析器使用的默认解析器配置,而无需编写任何代码或更改现有解析器类。 只需使用以下机制之一:

  • org.apache.xerces.xni.parser.XMLParserConfiguration系统属性设置为指向您要使用的配置。
  • org.apache.xerces.xni.parser.XMLParserConfiguration文件添加到应用程序的JAR META-INF/services/目录中。 该文件需要包含解析器配置的类名。 只要包含此文件的JAR文件出现在Xerces的JAR文件之前,解析器就会使用新的解析器配置。

XNI与SAX

如前所述,XNI提供了类似于SAX API的框架。 它也是一个基于事件的API,其中解析事件(例如元素的开始和结束)通过对处理程序的回调被推送到XNI组件和您的应用程序。

XNI处理程序接口旨在提供XML信息集规范定义的所有文档信息。 处理程序接口可以使用称为XNI Augmentations的结构来提供其他信息,例如后架构验证信息集(PSVI)。 XNI Augmentaions作为每个处理程序方法上的参数存在。 SAX 2.0.1和早期版本的SAX并未报告所有文档信息。 例如,以前的SAX没有用于检索正在解析的文档的编码的方法。 随着2004年初发布的SAX 2.0.2,现在报告了XML信息集中的所有信息。 现在,您可以从Locator2界面检索编码信息。

假设您的SAX应用程序始终在存在Xerces2的环境中运行,则可以直接切换到使用XNI进行编程,从而从中受益。 这不仅使您可以访问更多信息,还可以提高应用程序的性能。 正如我们在第2部分中提到的那样,Xerces2的SAX解析器有时必须执行其他处理。 例如,从解析器的内部表示中修改或删除名称空间声明属性,以符合SAX规范。 这带来了使用XNI可以避免的性能成本。

与SAX相比,用于访问文档信息集的XNI的设计在性能上进行了更多的调整。 要访问SAX中的某些信息,您需要将一个对象强制转换为另一个接口。 这会带来性能成本。 例如,要查询是在文档中指定了属性还是通过DTD设置了默认属性,您需要将org.xml.sax.Attributes转换为org.xml.sax.ext.Attributes2接口。 要访问XML文档的编码和版本,您需要将ContentHandler.setDocumentLocator(Locator)调用中提供的定位器对象Locator2转换为Locator2接口。 使用XNI,可以通过org.apache.xerces.xni.XMLDocumentHandler.xmlDecl方法将XML文档的编码和版本推送到应用程序。

在SAX中,对于每个名称空间声明,您的应用程序都会收到一个startPrefixMapping调用和一个相应的endPrefixMapping调用。 这意味着,如果您的XML文档包含相对大量的名称空间声明,则会获得许多其他回调,这会使应用程序变慢。 为了避免这种情况,XNI在一个对象( org.apache.xerces.xni.NamespaceContext )中提供了名称空间信息,该对象通过XNI文档处理程序的startDocument方法传递该名称空间。 如果以后需要访问当前名称空间信息,则应用程序负责保存此对象。

为什么还要考虑直接使用XNI? 例如,如果您的应用程序需要合并两个XML文档并针对XML Schema验证生成的文档,则可以创建一个新的XNI组件来拦截XNI文档处理程序事件并合并这两个文档。 然后,您将创建一个新配置(确保它具有公共的,无参数的构造函数),并将此组件放入XML Schema验证程序之前的解析管道中。 在此处使用XNI可以帮助您避免为文档的中间表示创建内存结构,将两个文档合并到内存中,可能会序列化生成的文档,然后要求解析器再次解析文档并进行验证。

Xerces2特性和属性:性能提示

在本节中,我们讨论Xerces2解析器特有的其他功能和属性,以及如何配置它们以提高应用程序的性能。

选择输入缓冲区大小

在解析器内部,许多缓冲区在解析文档时将其存储在内存中。 默认情况下,读取器中输入缓冲区的大小为2 KB。 这意味着一次将从输入流读取多达2 KB。 一些性能测试表明,当解析大于2 KB的文档时,增加此输入缓冲区的大小可以提高性能。 Xerces 2.1.0中引入了由URI http://apache.org/xml/properties/input-buffer-size标识的属性,使您可以校准输入缓冲区的大小以最适合XML文档的大小。 此属性的值是java.lang.Integer的实例,其单位值以字节为单位。

对于小型文档(通常小于4 KB),坚持使用默认的缓冲区大小将为您带来良好的性能。 对于较大的文档,应将属性设置为4 KB到8 KB之间,以实现最佳性能。 如果要分析2 KB以下的文档,则可能要选择小于2 KB的输入缓冲区。 对于大型文档,选择较大的缓冲区大小的好处会下降到8 KB以上,尽管这可能取决于传递给解析器的输入源的类型。

避免加载外部DTD

第1部分中 ,我们向您展示了如何使用SAX定义的标准功能来配置解析器,以避免处理外部通用和参数实体。 正如我们所讨论的,根据XML规范,验证处理器(例如Xerces2)必须同时处理内部和外部DTD子集。 Xerces2定义了由URI http://apache.org/xml/features/nonvalidating/load-external-dtd标识的功能,用于控制如果文档具有外部子集,是否将读取外部DTD子集。 如果您的应用程序不需要读取外部子集,请将此功能设置为false以提高性能。 如果您的应用程序需要谨慎使用此功能:

  • 需要查询属性类型
  • 对解析器针对非CDATA属性执行的空白折叠敏感
  • 依靠元素内容中的空白被报告为可忽略

如果启用了验证,则将忽略此功能的值,在这种情况下,始终会读取外部DTD子集。

禁用完整架构约束检查

如果您有为XML模式验证设置Xerces2的经验,您可能已经注意到,有两个功能会影响由URI http://apache.org/xml/features/validation/schemahttp://apache.org/xml/features/validation/schema-full-checking标识的模式验证。 http://apache.org/xml/features/validation/schema-full-checking 。 设置为true ,第一个功能启用架构验证。 W3C XML模式规范定义了许多约束,这些约束既耗时又需要占用大量内存。 这些包括粒子推导和唯一的粒子归因约束。 与第二个功能一起设置为true时,第二个功能可以检查这些更复杂的约束。 默认情况下, schema-full-checking功能的值为false 。 在开发架构语法时,应将此功能设置为true以便Xerces2将检查所有必要的约束以确定架构是否有效。 准备好部署应用程序后,将此功能设置为false 。 通过消除对更昂贵约束的检查,即使您已经在使用下面描述的语法缓存机制,也可以提高应用程序的性能。 应该注意的是,禁用schema-full-checking功能不会影响对实例文档执行的检查级别; 它仅适用于架构语法本身最昂贵的约束。

避免产生PSVI

W3C XML Schema规范定义了对XML信息集(称为Post-Schema-Validation Infoset(PSVI))的扩充。 PSVI是模式评估和验证的结果,它包括诸如元素已针对其进行验证的类型以及元素和属性的模式归一化值之类的属性。 默认情况下,Xerces2生成PSVI。 为了公开此信息,Xerces2实现了XML Schema API,该API提供了通过SAX和DOM对PSVI的访问。 如果您的应用程序无法使用JAXP指定的API之外的其他API,则解析器报告的PSVI将无法访问。 Xerces2定义了一个由URI http://apache.org/xml/features/validation/schema/augment-psvi标识的功能,该功能指定是否在模式验证期间生成PSVI。 如果您不会从PSVI中读取内容,请将此功能设置为false以避免生成PSVI。 当执行模式验证时,这将提高您的应用程序的性能。

缓存架构

如今,许多应用程序需要根据诸如DTD或W3C XML Schema之类的模式来验证XML文档。 验证是一个昂贵的过程,因为解析器不仅需要解析XML文档,而且还需要访问提供的一个或多个模式,然后解析并构建这些模式的一些内部表示形式。 为简单起见,我们将预编译模式并建立模式的内部表示的过程称为编译模式 。 然后,解析器使用编译的架构来验证XML文档。

如果您的应用程序要验证XML文档的模式集有限,请考虑编译和缓存模式,因为它可以显着提高应用程序的性能。 特别是,如果您的应用程序正在处理的大多数XML文档都相对较小(小于2K),那么编译模式将消耗XML文档总体处理时间的一半以上。

要缓存模式,您需要一个API,该API允许您编译模式并在解析器上进行设置。 坏消息是,在JAXP 1.3最终确定之前,没有标准的API可以做到这一点。 JAXP 1.3规范定义了一个简单的API,该API允许应用程序编译和缓存模式。 但是,如果您想缓存模式以提高当今应用程序的性能,则需要使用Xerces2特定的API。

Xerces2语法缓存API

默认情况下,Xerces2解析器不缓存架构(在Xerces术语中,架构称为语法 )。 为了允许应用程序优化性能,Xerces2定义了XNI语法API( org.apache.xerces.xni.grammars ),它允许您编译模式,创建包含这些模式的语法池,并在解析器中注册该语法池。

您的应用程序很可能不需要使用完整的XNI Grammar API来缓存架构。 相反,您可以使用默认的Xerces2语法缓存实现( org.apache.xerces.util.XMLGrammarPoolImpl ),它允许您被动地编译和缓存模式。 以下是默认实现的工作方式:

  1. Xerces2的解析器开始解析XML文档。
  2. 在开始验证之前,Xerces验证器(XML Schema或DTD验证器)将调用org.apache.xerces.xni.grammars.XMLGrammarPool接口的retrieveInitialGrammarSet(String)方法,以从注册的语法池中检索一组已编译的模式。 这些模式存储在验证程序的语法存储区中,并在需要时在验证期间使用。
  3. 在解析期间,如果验证器需要新的架构,它将首先检查语法存储桶是否具有所需的已编译架构。 对于XML模式,语法存储桶中的模式由targetNamespace URI键入; DTD键在根元素上。
  4. 如果在语法存储桶中未找到已编译的架构,则验证器会要求注册的语法池使用retrieveGrammar(XMLGrammarDescription)方法提供架构。 如果池没有返回任何模式,则验证器将尝试使用已注册的实体解析器(例如org.xml.sax.EntityResolver )或使用默认实体解析来解析模式。
  5. 解析结束时,验证器使用cacheGrammars(String, Grammar[])方法将语法存储桶中的所有编译模式返回到已注册的语法池。 这组已编译模式存储在语法池中,并在随后的解析中作为语法的初始集合提供给Xerces2验证器(如步骤2中所述 )。

因此,如果您使用默认实现,则无需提前编译架构。 换句话说,您的应用程序从一个空的语法池开始。 解析器将编译验证所需的任何新模式,并在XML文档的解析完成后将所有已编译的模式返回给语法池。 结果,前几个XML文档的处理可能很慢。 但是,假设您具有一组有限的模式,那么当您继续解析其他XML文档时,语法池最终将包括验证XML文档所需的所有已编译模式。 此时,解析器不再需要编译任何新的架构,并且对后续XML文档的验证不再承受编译架构的性能成本。

您可以通过两种方式触发Xerces2默认模式缓存实现:

  • 您可以指定语法缓存解析器配置( org.apache.xerces.parsers.XMLGrammarCachingConfiguration )。
  • 您可以使用URI http://apache.org/xml/properties/internal/grammar-pool标识的Xerces2属性在解析器上设置默认语法池实现( org.apache.xerces.util.XMLGrammarPoolImpl )。

正如我们在第2部分中讨论的那样,如果您希望在某些环境中您的应用程序在类路径上具有Xerces2,并且您的应用程序具有数量有限的模式,则应尝试触发语法缓存(如清单1所示),以便如果Xerces2解析器可用,则您的应用程序将性能更好。

清单1.触发模式缓存
...
	
XMLReader parser = XMLReaderFactory.createXMLReader();
    
try {
    Class poolClass =  
        Class.forName("org.apache.xerces.util.XMLGrammarPoolImpl");
        
    Object grammarPool = poolClass.newInstance();
        
    parser.setProperty(
        "http://apache.org/xml/properties/internal/grammar-pool", 
        grammarPool);          
}
catch (Exception e) {}

提供自己的语法池实现

在某些情况下,您可能想提供自己的语法池实现。 例如,假设您的应用程序计划处理可能包含非重复模式的XML文档。 您可能不希望解析器将所有已处理的架构添加到默认语法池,因为这最终可能导致虚拟机用完内存。 相反,您可能想要编译最常用的模式子集,然后锁定池(请参阅XMLGrammarPool lockPool()方法)以禁止将新的模式添加到池中,如清单2所示。

清单2.预准备模式
// create grammar preparser
XMLGrammarPreparser preparser = new XMLGrammarPreparser();

// register a specialized pre-parser
preparser.registerPreparser(XMLGrammarDescription.XML_SCHEMA, null);

// create grammar pool
XMLGrammarPool grammarPool = new XMLGrammarPool();

// set the grammar pool on the grammar preparser 
// so that all the compiled grammars are automatically
// placed to the grammar pool
preparser.setProperty(GRAMMAR_POOL, grammarPool);

// set properties
preparser.setFeature(NAMESPACES_FEATURE_ID, true);
preparser.setFeature(VALIDATION_FEATURE_ID, true);

// parse grammar(s)
Grammar g = preparser.preparseGrammar(
    XMLGrammarDescription.XML_SCHEMA, 
    new XMLInputSource(null, "personal.xsd", null));

// lock grammar pool
grammarPool.lockPool();

// next register the grammar pool with the parser
// and start parsing
...

结论

在本文中,我们介绍了Xerces本机接口(XNI),并描述了如何直接使用此API来提高应用程序的性能。 然后,我们讨论了Xerces2特有的几种功能和特性,以及如何校准它们以加快文档处理速度。 最后,我们向您展示了如何使用Xerces2缓存模式,以避免重复处理它们的成本。

这个由三部分组成的系列文章中介绍的技术应有助于您在编写XML应用程序时做出更高的性能。 当然,我们没有涵盖许多其他技术。 请记住,在一个特定的解析器实现中可能会表现良好的结果可能在另一个特定的解析器中却表现不佳,反之亦然,因此,您可能需要做一些实验以获得最佳性能。


翻译自: https://www.ibm.com/developerworks/xml/library/x-perfap3/index.html

xml应用程序下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值