zoukankan      html  css  js  c++  java
  • 用XMLTask操作XML

    《Java开发超级工具集》第1章用Ant设置项目,XMLTask是比标准或文件创建任务强大得多的工具,使用它可以维护、创建和修改XML文件,同时还不必担心会使用XSLT。本节为大家介绍用XMLTask操作XML。

     

     用XMLTask操作XML(1)

    本节作者:Brian Agnew

    对于简单的文本搜索和替换操作,Ant的<replace>任务就够用了,但在现代Java框架中,用户更可能需要强大的XML操作能力来修改servlet描述符、Spring配置等。

    XMLTask是Ant外部任务,它提供了强大的XML编辑工具,主要用于在构建/部署过程中创建和修改XML文件。

    使用XMLTask的好处如下?

    与Ant的<replace>任务不同,XMLTask使用XPath提供识别XML文档各个部分的能力,并且还能在这些位置插入、删除和复制XML。用户可以使用XPath简单地识别XML元素或者用谓词(predicate)执行更复杂的逻辑(如“查找有‘Y’属性的名为‘X’的元素……”)。

    XMLTask了解XML,这意味着用户不能创建格式混乱的XML文档,XMLTask将处理字符编码问题,而<replace>不知道XML文档的编码需求。例如,<replace>允许用户不使用对应实体(“<”、“>”和“&”)就能将“<”、“>”和“&”等字符插入到XML文档中,从而可能破坏文档的良好格式。

    为了执行XML操作,XMLTask不要求用户学习或使用XSLT,它使用直观的指令如insert、replace和remove。

    XMLTask易于使用。可以访问其主页(注5)或者从Sourceforge上(注6)下载它。要使用XMLTask不需要精通XPath,但如果需要相关介绍,可以查阅http://www.zvon.org/(注7)中的入门教程。

    示例

    下面介绍一个简单的例子。假设用户想修改一个Spring配置,目的是开发、测试和发布版本而进行修改,并想要执行插入、替换和删除操作。

    以下是一个简单的XMLTask任务:

    1. <project name="xmltask-demo" default="main">   
    2.  <!--xmltask.jar should be referenced via lib, 
      or in the ${ant.home}/lib or similar  
    3.     --> <taskdef name="xmltask" classname="com.
      oopsconsultancy.xmltask.ant.XmlTask"
      />   
    4.    
    5.  <!-- you may need to reference a local copy of 
      the DTD here 
      if your XML   
    6.          documents specify one. See below for more info -->   
    7.  <xmlcatalog id="dtd">   
    8.      <dtd   
    9.         publicId="-//SPRING//DTD BEAN//EN"   
    10.        location="./spring-1.0.dtd"/>   
    11.  </xmlcatalog>   
    12.    
    13.  <target name="main">   
    14.    <xmltask source="spring-template.xml" dest="
      spring.xml"
       preserveType="true">   
    15.      <xmlcatalog refid="dtd"/>   
    16.      <insert path="/beans" position="under">   
    17.           <![CDATA[   
    18.             <bean id="bean-to-insert" class="com.
      oopsconsultancy.example.Bean1"
      >  
    19.                <constructor-arg index="0">   
    20.                  ...   
    21.                </constructor-arg>   
    22.             </bean>   
    23.            ]]>   
    24.      </insert>   
    25.    </xmltask>   
    26.   </target>   
    27. </project> 

    像引用任何外部任务一样,使用<taskdef>来引用XMLTask任务。

    在<xmltask>任务中指定源XML文件和目标XML文件,XMLTask将从源XML中读取内容,应用用户所配置的XMLTask指令,然后将XML写入目标文件。

    每条指令识别一组匹配的XML元素(使用XPath),并在每个元素上执行操作。例如,<insert>指令将在由XPath指定的所有匹配XML元素上执行插入操作(使用XPath可以将操作限制为第一个匹配元素、最后一个匹配元素,诸如此类)。

    指令集将顺序执行,因此,可以先指定插入操作,然后指定替换操作,再指定删除操作。

    以上示例在spring-template.xml文件中的<beans>根元素下插入了一个Spring bean定义,并将结果写入spring.xml文件。假设spring-template.xml文件是如下所示的空配置文件:

    1. <?xml version="1.0" encoding="UTF-8"?>   
    2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
      "http://www.springframework.org/dtd /spring-beans.dtd">   
    3. <beans>   
    4. </beans>  

    在运行上面给出的<xmltask>任务后,用户的spring.xml文件将类似于以下形式:

    1. <?xml version="1.0" encoding="UTF-8"?>   
    2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"   
    3.      "http://www.springframework.org/dtd /spring-beans.dtd">   
    4.      <beans>   
    5.      <bean id=”bean-to-insert” class=”com.oopsconsultany.example.Bean1”   
    6.      dependency-check="default"   
    7.      lazy-init="default" singleton="true">   
    8.              <constructor-arg index=”0”>   
    9.              ...  
    10.              </constructor-arg>   
    11.      </bean>   
    12. </beans> 

    注意,在DTD中指定的有默认值的属性将生成并插入到输出XML中(并将其相应设置为默认值 —— 如dependency-check、lazy-init和singleton)。

    不必一定在Ant构建文件中指定XML,可以从文件中引用它。例如,可以将bean定义存储在development-bean.xml文件中,并使用以下代码将development-bean.xml的内容插入到Spring配置中:

    1. <insert path="/beans" position="under" 
      file=
      "development-bean.xml"

    到目前为止,这些操作都相对简单,但用户可以执行更复杂的操作。例如,如果想要修改以下Spring数据源bean的登录信息:

    1. <bean id="ExampleDataSource" class="org.
      apache.commons.dbcp.BasicDataSource"
         
    2. destroy-method="close">   
    3. <property name="driverClassName" ref="db-driver-name"/>         
    4. <property name="url" value="..."/>   
    5. <property name="username" value=""/>   
    6. <property name="password" value=""/>   
    7. </bean> 

    可以使用<replace>操作插入来自${dev.username}和${dev.password}属性中的用户名和密码:

    1. <xmltask source="spring-template.xml" dest=
      "spring.xml" preserveType="true">   
    2.   <replace path="/beans/bean[@id='
      ExampleDataSource']/property[@name='username']/@value"
       
    3.   withText="${dev.username}"/>   
    4.   <replace path="/beans/bean[@id='
      ExampleDataSource']/property[@name='password']/@value"
       
    5.   withText="${dev.password}"/>   
    6. </xmltask>  

    注意,通过使用谓词,此示例使用XPath指定要修改哪个bean(ExampleDataSource),XPath表达式指定“查找有特定id的bean,在其下找到有给定名称的属性”,从而允许用户修改特定元素的属性。

    也可以删除XML,例如,用户可能想要删除所有test bean:

    1. <remove path="/beans/bean[contains(@id, 'Test')]"/> 

    这将从用户的Spring配置中删除所有id中有test的bean。

    DTD和XMLTask

    在以上示例中指定了一个DTD的本地版本。如果是在源文档中指定DTD,XMLTask需要访问该DTD执行实体替换。如果直接连接到了Internet,那么,XMLTask和其他工具可以透明地获得DTD。不过,如果没有直接连接到Internet或者连接速度有问题,可能将需要指定一个本地副本(或者告诉XMLTask该DTD不可用)。

    这很简单,只需要指定一个Ant <xmlcatalog>标签。例如,以下代码指定了一个Servlet DTD和一个本地副本:

    1. <xmlcatalog id="dtd">   
    2.    <dtd publicId="-//Sun Microsystems, 
      Inc.//DTD Web Application 2.3//EN"
         
    3.       location="./servlet-2.3.dtd"   
    4.    />   
    5. </xmlcatalog> 

    此段代码用特定的公共ID指定了DTD的一个本地副本(servlet-2.3.dtd)。

    然后,在<xmltask>调用中引用该副本:

    1. <xmltask  
    2.    source="src/web.xml" dest="target/web.xml"   
    3.    preserveType="true">   
    4.   <xmlcatalog refid="dtd"/>   
    5.     ... 

    输出文档应该使用哪个DTD取决于如何操作源文档。大多数情况下,目标文档将匹配源文档的DTD。在这种场景下,可以告诉XMLTask在目标文档中生成与源文档相匹配的DTD指令:

    1. <xmltask   
    2. source="src/web.xml" dest="target/web.xml"   
    3. preserveType="true"

    在其他情况下,如从头创建文档或者对源文档进行了大量修改,将需要指定DTD公共和系统标识符:

    1. <!-- we're creating a 2.3 web.xml document from scratch -->   
    2. <xmltask   
    3.    source="src/web.xml" dest="target/web.xml"   
    4.    public="-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"   
    5.    system="http://java.sun.com/dtd/web-app_2_3.dtd"

    通过XMLTask驱动Ant

    可以用XMLTask读取XML文件,并利用这一点为每个指定的XML元素调用不同的Ant目标,这样就能通过外部配置文件驱动构建的各个部分。该文件可能表示用户想要构建的环境、需要测试的类或者需要处理的文件目录等。

    例如,假设需要运行一组测试类,这些类封装在一个配置XML文件中:

    1. <environments>   
    2.    <env name="Test Scenario 1" enabled="true">   
    3.      <class>com.oopsconsultancy.example.TestScenario1</class>   
    4.      <db>database1</db>   
    5.     <results>development/test/scenario1.txt</results>   
    6.    </env>   
    7.    <env name="Test Scenario 2" enabled="true">   
    8.      <class>com.oopsconsultancy.example.TestScenario2</class>   
    9.      <db>database2</db>   
    10.     <results>development/test/test_data_2.txt</results>   
    11.    </env>   
    12. </environments> 

    每个环境都有一个测试类、一个测试数据库和一个结果文本文件。

    可以使用XMLTask遍历此文件,并执行每个测试类以执行相应的测试:

    1. <!-- XMLTask only needs a source here, since it's only reading -->   
    2. <xmltask source="environments.xml">   
    3.    <call path="/environments/env[@enabled='true']" target="execute-tests">   
    4.       <param name="class" path="class/text()"/>   
    5.       <param name="db" path="db/text()" default="devDb"/>   
    6.       <param name="results" path="results/text()"/>   
    7.    </call>   
    8. </xmltask>   
    9.  
    10. <target name="execute-tests">   
    11.    <echo>Running ${class} against ${db}, results in ${results}</echo>   
    12.    <!-- run the appropriate tests -->   
    13. </target> 

    对于由/environments/env标识的每个XML元素(enabled属性为true),XMLTask都将调用Ant的execute-tests目标,每个被调用的Ant目标都使用读取的XML文件内容设置其属性。每次调用execute-tests目标时,XMLTask都会将${class}属性设置为该XML元素指定的类、将${db}属性设置为该元素指定的数据库,同时还将${results}属性设置为所需的结果文件。

    如果运行以上代码,将会看到以下输出:

    1. Running com.oopsconsultancy.example.TestScenario1
      against database1, results in   
    2.  development/test/scenario1.txt   
    3. Running com.oopsconsultancy.example.TestScenario2 
      against database2, results in   
    4.  development/test/test_data_2.txt 

    其他技巧

    更改编码

    可以更改XML文件的字符编码:

    1. <xmltask source="windows-encoded.xml" dest="16bit-unicode-encoded.xml"   
    2. encoding="UnicodeBig"/> 

    UnicodeBig是16位Unicode编码(big-endian)的编码代码,有关XML支持的编码信息,请访问http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html。这将在输出时把XML文档转换为16位Unicode编码的文档。注意,不必定义任何指令,因为XMLTask只是简单地读入文档再将其输出。

    维护有注释的文档

    使用XMLTask可去掉XML文件中的注释,这意味着用户可以维护有多个注释部分的配置文件,并在部署时去掉所需部分的注释。例如:

    1. <configurations>   
    2.  <!--  
    3.  <configuration env="dev">   
    4.  ...   
    5.  </configuration>   
    6.  -->   
    7.  <!--  
    8.  <configuration env="test">   
    9.  ...   
    10.  </configuration>   
    11.  -->   
    12.  <!--  
    13.  <configuration env="prod">   
    14.  ...   
    15.  </configuration>   
    16.  -->   
    17. </configurations>   
    18. <!--  
    19. <xmltask source="source.xml" dest="dest.xml" >   
    20.  <uncomment path="/configurations/comment()[2]"/>   
    21.  ...   
    22. </xmltask> 

    这启用了第二个注释部分(注意,XPath是从元素1而不是0开始索引元素的)。因此,每个被部署的文档都将有相同的注释部分,但只一个部分需要被取消注释,在必须比较部署的不同版本及其之间的差别时,这会使用户的工作轻松得多。

     

    小结

    XMLTask是比标准<replace>或文件创建任务强大得多的工具,使用它可以维护、创建和修改XML文件,同时还不必担心会使用XSLT。有许多XMLTask的功能这里没有介绍,关于它的更多信息和示例可以访问其主页(http://www.oopsconsultancy.com/software/xmltask),另外还可以获得邮件列表(http://lists.sourceforge.net/lists/listinfo/xmtask-users,需要订阅)。

     

    Desire has no rest.
  • 相关阅读:
    顺序表与链表
    Python SQL相关操作
    Python 数据分析练习1
    Python 操作MySQL数据库
    Python 乘法口诀表
    Python 导出数据from Mysql
    Python subplot 绘画
    Shell 自定义函数
    Shell 双括号概述
    Shell for、while循环
  • 原文地址:https://www.cnblogs.com/samcn/p/2100023.html
Copyright © 2011-2022 走看看