code_money_guji's Blog

Happy coding

Groovy Process Xml(创建XML)

参考资料:

               http://groovy.codehaus.org/Creating+XML+using+Groovy%27s+MarkupBuilder

         NOTE: 这是笔者的备忘录BLog,如果代码有运行不成功的, 请访问上面给出的链接. 感谢Groovy社区的所有Groovy Monkey 谢谢!

Groovy处理XML之创建XML:

  一 简单的创建实例:

   

def stringWriter = new StringWriter();  
def xml = new MarkupBuilder(stringWriter);
//红色表示元素, 绿色表示属性, 黄色表示元素的text值
xml.cars() {
	   car(name:"car1",no:"1") {
		     country('china')
	                  city('kunming')
		   }
	   
	   car(name:"car2",no:"2") {
		   country('china')
		   city('kunming')
		 }
	   
	   car(name:"car3",no:"3") {
		   country('china')
		   city('kunming')
		 }
	
	}

println stringWriter 
//打印结果如下:
<cars>
  <car name='car1' no='1'>
    <country>china</country>
    <city>kunming</city>
  </car>
  <car name='car2' no='2'>
    <country>china</country>
    <city>kunming</city>
  </car>
  <car name='car3' no='3'>
    <country>china</country>
    <city>kunming</city>
  </car>
</cars>

对比示例程序和输出的结果看出:
 1 一个方法表示一个Element;
 2 方法中的参数代表此ELement的Attributes[propertyName:propertyValue]
 3 方法中如果propertyName 和propertyValue不是成对出现,只是出现了propertyValue,那么将会被设置为ELement的text值.

二 使用DomToGroovy类,将一个现有的XML转化Groovy MakeUpBuilder的相关代码:
class XmlExamples {
	static def CAR_RECORDS = '''
	  <records>
		<car name='HSV Maloo' make='Holden' year='2006'>
		  <country>Australia</country>
		  <record type='speed'>Production Pickup Truck with speed of 271kph</record>
		</car>
		<car name='P50' make='Peel' year='1962'>
		  <country>Isle of Man</country>
		  <record type='size'>Smallest Street-Legal Car at 99cm wide and 59 kg in weight</record>
		</car>
		<car name='Royale' make='Bugatti' year='1931'>
		  <country>France</country>
		  <record type='price'>Most Valuable Car at $15 million</record>
		</car>
	  </records>
	'''
  }
  
//使用DomToGroovy进行反向的转化:
import javax.xml.parsers.DocumentBuilderFactory
import org.codehaus.groovy.tools.xml.DomToGroovy

def builder     = DocumentBuilderFactory.newInstance().newDocumentBuilder()
def inputStream = new ByteArrayInputStream(XmlExamples.CAR_RECORDS.bytes)
def document    = builder.parse(inputStream)
def output      = new StringWriter()
def converter   = new DomToGroovy(new PrintWriter(output))

converter.print(document)
println output.toString()
打印出的结果如下:
//红色表示元素, 绿色表示属性, 黄色表示元素的text值
records() {
  car(make:'Holden', name:'HSV Maloo', year:'2006') {
    country('Australia')
    record(type:'speed', 'Production Pickup Truck with speed of 271kph')
  }
  car(make:'Peel', name:'P50', year:'1962') {
    country('Isle of Man')
    record(type:'size', 'Smallest Street-Legal Car at 99cm wide and 59 kg in weight')
  }
  car(make:'Bugatti', name:'Royale', year:'1931') {
    country('France')
    record(type:'price', 'Most Valuable Car at $15 million')
  }
}

三 为创建的XML添加NameSpace
实例代码: 
def xml = new MarkupBuilder(writer)
xml.'rec:records'('xmlns:rec': 'http://groovy.codehaus.org') {
  car(name:'HSV Maloo', make:'Holden', year:2006) {
    country('Australia')
    record(type:'speed', ' Truck with speed of 271kph')
  }
}

result

<rec:records xmlns:rec='http://groovy.codehaus.org'>
  <car name='HSV Maloo' make='Holden' year='2006'>
    <country>Australia</country>
    <record type='speed'> Truck with speed of 271kph</record>
  </car>
</rec:records>

=================================
xml.records(xmlns: 'http://groovy.codehaus.org') {
  car(name:'HSV Maloo', make:'Holden', year:2006) {
    country('Australia')
    record(type:'speed', ' Truck with speed of 271kph')
  }
}

result

<records xmlns='http://groovy.codehaus.org'>
  <car name='HSV Maloo' make='Holden' year='2006'>
    <country>Australia</country>
    <record type='speed'> Truck with speed of 271kph</record>
  </car>
</records>


四 使用Groovy的StreamingMarkupBuilder创建XML:
示例代码:

import groovy.xml.StreamingMarkupBuilder

 def xml = new StreamingMarkupBuilder().bind {
    root {
      a( a1:'one' ) {
        b { mkp.yield( '3 < 5' ) } //注意点
        c( a2:'two', 'blah' )
      }
    }
  }
 
 println xml.toString();
 程序运行结果:
  <root>
      <a a1='one'>
          <b>3 < 5</b>
          <c a2='two'>blah</c>
      </a>
  </root>
  
五 使用Groovyapi结合Dom创建XML
   参考链接:http://groovy.codehaus.org/Creating+XML+with+Groovy+and+DOM


 

Groovy 集合类常用api之List篇

参考资料:

         <<Programming Groovy>>

          DefaultGroovyMethods源代码

 

Groovy collection 常用api之List篇:

     1 each 

 each 源代码<私有方法>:
 private static <T> Iterator<T> each(Iterator<T> iter, Closure closure) {
        while (iter.hasNext()) {
            closure.call(iter.next()); // 在闭包中改变it这个默认参数是达不到更改集合的效果的.
        }
        return iter;
    }

each 将集合中的每一个元素传递到闭包中执行,也就是闭包直接修改元素,并且是执行一个iterator,注意多线程同时修改引发的异常. 最终将处理完毕的List
返回,注意,在闭包中使用 it = "changedValue"是不会有效的!  例如:
def list = ["1",2,3,54]
list.each{
          if(it.equals("1")){
                //try to change the value,but it is noe affect the list!!
                it = "changed"
               
              }
    }
assert list == ["1",2,3,54]

如果想要得到闭包修改以后的集合,使用方法: collect

      2 collect: 使得每一个集合元素都参与闭包的运算,并最终返回一个新的集合,此集合的每一个元素都是闭包执行后的结果.

源代码:<私有方法>
 public static Collection collect(Collection self, Collection collection, Closure closure) {
        for (Iterator iter = self.iterator(); iter.hasNext();) {
            collection.add(closure.call(iter.next()));
            if (closure.getDirective() == Closure.DONE) {
                break;
            }
        }
        return collection;
    }

测试:

def list = [1,2,3,4]
assert list.collect {
        it * 2;    
     }  == [2,4,6,8]
//原来的集合不变    
assert list == [1,2,3,4]

      3 find方法以及findAll方法: 注意,find方法只查找第一个

   源代码: 
    public static Object find(Object self, Closure closure) {
        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
            Object value = iter.next();
            if (DefaultTypeTransformation.castToBoolean(closure.call(value))) { //如果满足条件
                return value; //只是返回第一个
            }
        }
        return null; //不满足闭包调价就返回null
    }

  测试代码:

  def list = [1,2,3,4]
  assert 1 == list.find {
           it < 5 //表明闭包会返回一个boolean
     }
 //原来的集合不变
assert list == [1,2,3,4]

====================findAll
<源代码>
 private static <T> Collection<T> findAll(Closure closure, Collection<T> answer, Iterator<T> iter) {
        while (iter.hasNext()) {
            T value = iter.next();
            if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
                answer.add(value); //把符合闭包条件的元素添加到新的集合answer中.
            }
        }
        return answer;
    }


       4 inject 方法: 每次都会传入value和每一个集合元素给闭包,并返回闭包的执行结果,注意,闭包对应的参数是一个object[2],要有两个参数 

 public static Object inject(Iterator self, Object value, Closure closure) {
        Object[] params = new Object[2];
        while (self.hasNext()) {
            Object item = self.next();
            params[0] = value;
            params[1] = item;
            value = closure.call(params);
        }
        return value;
    }

 测试代码:
def list = [1,2,3,4]
assert list.inject(1) {
            param1,
            param2
            ->
           
            param1 + param2;
     }  == 11 //(1+1,2+2,4+3,7+4),最终为11 


            5 一些辅助的集合方法:

        5.1 sum()方法:

def list = [1,2,3,4]
assert list.sum() == 10
//代闭包的sum方法;
assert list.sum{
             it * 2	
	} == 20

       5.2 join()方法: 将集合合并

def list = [1,2,3,4]
assert list.join().class == String 
assert list.join() == "1234"
//带上分隔符
assert list.join('|') == "1|2|3|4"

       5.3 flatten方法:

 先将测试代码贴出;
 def list1 = [["Be" , "Productive" ], "In" , "Groovy" ];
 assert list1.flatten() == ["Be" , "Productive" , "In" , "Groovy" ]
 
 源代码贴出:
   DefaultGroovyMethods类中的代码:
   private static Collection flatten(Collection elements, Collection addTo) {
        for (Object element : elements) {
            if (element instanceof Collection) {
                flatten((Collection) element, addTo);
            } else if (element != null && element.getClass().isArray()) {
                flatten(DefaultTypeTransformation.arrayAsCollection(element), addTo);
            } else {
                // found a leaf
                addTo.add(element);
            }
        }
        return addTo;
    }

  DefaultGroovyMethodsSuport中的代码贴出:[这里只是贴出有关List的,map,set的请参考相关源代码]
  protected static <T> List<T> createSimilarList(List<T> orig, int newCapacity) {
        if (orig instanceof LinkedList)
            return new LinkedList<T>();

        if (orig instanceof Stack)
            return new Stack<T>();

        if (orig instanceof Vector)
            return new Vector<T>();

        return new ArrayList<T>(newCapacity);
    }

  

      5.4 groupBy方法: public static <T> Map<Object, List<T>> groupBy(Collection<T> self, Closure closure)  方法根据传入的闭包执行以后, 闭包执行的结果被

          封装为一个Map Entry的key,集合元素被封装为对应key的value. 源代码如下:

   public static <T> Map<Object, List<T>> groupBy(Collection<T> self, Closure closure) {
        Map<Object, List<T>> answer = new LinkedHashMap<Object, List<T>>(); //创建相关的MAP
        for (T element : self) {
            Object value = closure.call(element);//执行闭包,并保存闭包的执行结果到value
            groupAnswer(answer, element, value);
        }
        return answer;
    }

 //下面是groupAnser的源代码:
    protected static <T> void groupAnswer(final Map<Object, List<T>> answer, T element, Object value) {
        if (answer.containsKey(value)) {
            answer.get(value).add(element);
        } else {
            List<T> groupedElements = new ArrayList<T>(); //如果闭包的执行结果value不存在Map的keySet中,
             建立一个新的ArrayList存放对应集合元素
            groupedElements.add(element);
            answer.put(value, groupedElements);//加入Map中.
        }
    }

      5.5 count函数: 计算传入参数值匹配的个数,相当于在一个集合中统计出现元素的次数. 示例代码:     

         assert [2,4,2,1,3,5,2,4,3].count(4) == 2

  

     

Grails (一)

参考资料:

           InfoQ ----- Grails 入门指南:

                  http://www.cjsdn.net/doc/jvm/grails/docs/1.1/guide/2.%20Getting%20Started.html#2.5%20Getting%20Set-up%20in%20an%20IDE Grails Getting Started

 

Grails 安装配置:

 1 下载grails : http://grails.org/Download  获取grails

 2 解压, 类似JDK一样配置:GRAILS_HOME=%groovy_install_root%;

           并将%groovy_install_root%bin 追加到PATH环境变量中[注: %groovy_install_root%是grails解压后的目录];

 3 cmd  运行 grails 以检查配置的正确性;

 

 创建Grails项目

   到达你指定的一个grails work space, 在cmd中cd 到此目录,运行命令: grails create-app <your_app_name>;

   从命令的执行信息看出grails会去下载一些jar包,包括了spring,Hibernate ,commons-*,ejb3,servlet,以及日志jar包等等; 其实,在你解压

   的grails目录下面的lib目录中就有相关的jar包,之所以create-app命令执行比较快是因为其不用网络下载. 就向maven引用本地jar包一样. 此

   目录的输出是: 建立C:\Documents and Settings\User\.grails 目录;

                 建立C:\Documents and Settings\User\.ivy2 目录[包含jar包]

                 建立相关的工程目录如下截图:

  

 

 

 

 

 

             可以看到.classpath文件和.project文件.  可以带入到eclipse当中; 导入的时候, 可能会报错: 无法找到groovy.lang.GroovyObjectjar包,

             此时可以到C:\Documents and Settings\User\.ivy2中找到groovy-all的依赖包. 工程加入jar包以后就没问题了.

 

 创建相关的领域模型:

  上一个步骤创建了相关的目录结构,在grails中,是使用"惯例大于配置"的方式. 使用这样的方式可以省去很多繁琐的配置文件信息. 具体每个目录代表什么意思,

  请参考: http://www.cjsdn.net/doc/jvm/grails/docs/1.1/guide/2.%20Getting%20Started.html#2.5%20Getting%20Set-up%20in%20an%20IDE

  下面创建一个User 类的domain model:

              cd <刚刚创建的app目录>
              grails create-domain-class com.hcl.domain.Student 

   上面的命令告诉grails,在<your-app-root-dir>\grails-app\domain 下面创建一个包:com.hcl.domain 再创建一个类:Student.groovy 由于Grails是敏捷开发的工具,

   避免不了TDD的思想,于是,grails还会在工程<your-app-root-dir>\test\unit 下面添加单元测试文件com.hcl.domain.StudentTests.Groovy.如下截图:

    

   注意,当你将工程导入Eclipse的时候,加入依赖的jar包[截止此步骤至少含有的jar包]:  

    

   开始编写你的Student类吧,如果使用过Hibernate, 就应该很快了. 首先看看grails生成的Student.groovy文件:

 

class Student {

    static constraints = {
    } 
}

static constrants是grails自动生成的, 至于作用是什么,等等再介绍.
下面考试添加一些属性:
class Student {

    String studentName;
    long studentNumber;
    Integer studentAge;
    Date studentBirthDay;
    String studentPhone;
    
    static constraints = {
    }
}

使用哪个同样的方式[grails create-domain-class com.hcl.domain.Teacher],或者直接在Eclipse上创建相关的脚本文件Tearch:

class Teacher {

    String teacherName;
    String teacherNumber;
    Integer teacherAge;
    String teacherPoneNumber;
    
    static constraints = {
    }
}

NOTE: [下面给出一些比较犀利的使用方法, 只是作为提醒, 如果使用到,就到官方文档库里面搜搜吧.]

      1  Grails允许你定义一些特殊地位字段,所谓特殊就是grails会对这些字段进行"特殊关照". 例如: Date dateCreated 和 Date lastUpdated 等等.
         详细说明请参考相关给出的文档;
      
      2  Grails允许你使用Groovy闭包来定义相关的一些类似"触发器"的程序; 

      3 在static mapping ={..}闭包中,可以使用"sort "Property" " 之类的结果映射附加操作. 
        请参考:http://grails.org/GORM+-+Mapping+DSL 这篇文档;




 

创建Controller:

   使用 grails create-controller com.hcl.controllers.Student 来创建一个关于Student的控制器. grails会自动在Student后面加上

   Controller: StudentController

   

class StudentController {

    def index = { }
 }

命令同样会生成相关的测试类:
import grails.test.*

class StudentControllerTests extends ControllerUnitTestCase {
    protected void setUp() {
        super.setUp()
    }

    protected void tearDown() {
        super.tearDown()
    }

    void testSomething() {

    }
}

当然,同样需要将相关的依赖jar包导入, jar包路径和在生成domain的时候一样的方式寻找.
在StudentController中添加代码如下:
    def index = {
        render("Hello ,Grails World!");
        }
    
    def helloStudent = {
        render("Hello Student!");
        }
现在可以启动项目了, 可以首先使用:grails help 命令查看grails的相关命令,发现:grails run-app 然后敲此命令:
打开浏览器:

http://localhost:8080/<your_app_name>/student[注意,student是我们创建的controller],这个时候浏览器显示:

"Hello,Grils World!"

敲入:  

 http://localhost:8080/<your_app_name>/student/helloStudent [helloStudent是在StudentController中添加的一个闭包] 验证一下是否打印出"Hello Student!"

通过上面的运行结果看出:
 Grails 首先去找你的conreoller,找到以后再找你url后面跟着的groovy闭包名称, 然后执行. 最后使用render("")方法渲染页面. 
 整个过程没有任何配置文件的干预, 可见上面叫"约定大于配置"原则.

再看看一个相当神奇的controller属性: <添加一个属性到StudentController.groovy文件>如下: def scaffold = Student;
添加完毕以后注意引入包:import com.hcl.domain.* 并且把相关的闭包都去掉!!!; 代码如下:
class StudentController {

	def scaffold = Student;

//注意把下面的闭包注释掉:	
//    def index = { 
//		render("Hello ,Grails World!");
//		}
//	
//	def helloStudent = {
//		render("Hello Student!");
//		}
}


进入:http://localhost:8080/racetrack/student/  截图如下[现在暂时没有数据,如果有数据,会是一个关于Student的列表!!!]:

点击右边的"New Student" ,截图如下: 看到了么? 神奇的地方时只用了一个def scaffold = Student;属性.

 

Groovy Process Xml(解析XML)

参考资料:

       http://groovy.codehaus.org/Processing+XML  官方Groovy xml 操作

 

测试的xml文件内容:

<?xml version="1.0" encoding="UTF-8"?>
<books location="theLocation">
  <book bookid="1" mark="4">Java in action</book>
  <book bookid="2" mark="3">Groovy in action</book>
  <book bookid="3" mark="2">JavaScript in action</book>
  <book bookid="4">
      <position url="http://">
         <property name="propertiName1">Hello</property>
         <property name="propertiName2">World</property>
      </position>
  </book>
</books>

解析XML示例1:

def books = new XmlParser().parse("testXml.xml"); //参见groovy.util.XmlParser类的api

println langs.attributes().get("location");
//下面的语句更加具有"魅力",因为book是xml中的一个Element,Groovy能够很清楚的知道它是一个Node.
books.book.each {
	            def bookid = it.attributes().get("bookid"); 
				println bookid;  
	 }

 

解析XML示例二: 使用数组的下标直接定位;

def books = new XmlParser().parse("testXml.xml");
def bookCollection = books.book;
def book = bookCollection[0];
assert book.text() == "Java in action";
assert book.'@bookid' == "1";

 

解析XML示例三: 解析示例xml中Position

def file = new XmlParser().parse("testXml.xml");
def books = file.book;
def specialBook = books[3];

assert specialBook.'@bookid' == "4";
def properties = specialBook.position[0].property; //获取position的值;

properties.each {
	   println "-------------------" 
	   println it.'@name';
	   println it.text();
	   println "-------------------"
	}

 

解析XML示例四: 挑选合适的集合并使用排序的方式:

xmlFile.book.findAll {
	        it.attributes().keySet().contains("mark"); //先找到含有"mark"的标签, 因为有一个book是没有这个属性的,
                                                                                  //为了避免有些操作会抛出NullPointException.
	 }.sort{
	        it.'@mark'.toInteger(); //排序的依据
	 }.each {
	       println it.'@bookid';
	  }

 

结束语: 在groovy的文档中,还有很多的方便的解析方式, 这里只是使用了XmlParser这个类来解析.其他的方式可参考Groovy文档,很齐全!

 

Groovy IO

参考资料:

            http://groovy.codehaus.org/groovy-jdk/java/io/File.html   Groovy JDK File 文档;

           http://groovy.codehaus.org/JN2025-Streams  Groovy 官方文档之IO操作

前言: 文章内容收集自互联网以作备忘, 感谢各位作者的支持.

 

Groovy IO 操作:

 

1 将文本放置到一个String 对象中.      

def textFileContent;

   try{
	     textFileContent = new File("testFile.txt").getText();
	}catch(IOException e){
	   println "系统找不到文件";
	}
	

 

2 使用闭包操作:

  try{
	  def fileContent = new File("testFile.txt").eachLine { 
		           println it.getClass();       
		   }
	
	}catch(Exception e){
	     e.printStackTrace();
		 }

 

3 将文件内容用List收集:

	 try{
		     def fileContentAsList = new File("testFile.txt").readLines();
		     assert fileContentAsList.getClass() == java.util.ArrayList.class;
		 }catch(Exception e){
		     e.printStackTrace();
		 }

 

4 用特殊的字符分割每一行<ArrayList>,使用内敛函数操作:

  try{
	     text = new File("testFile.txt").splitEachLine(',') {
			      //do you code 
			  }
	}catch(Exception e){
	   e.printStackTrace();
	 }

 

5 处理二进制文件:

new File("foo.bin").eachByte { ... }

 

6 文件的写操作:

new File("testFile.txt").write("...");
----文件的追加
new File("foo.txt").append("...");