Advertisement
Garry_Galler

xmljoin

Jun 9th, 2016
213
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Nim 5.92 KB | None | 0 0
  1. {.boundChecks: on.}
  2.  
  3. import xmlparser,xmltree
  4. import os,strutils,sequtils
  5. import terminal
  6. #------------------------------------------------
  7. var
  8.   xml:       XmlNode
  9.   fHandle:   File
  10.   encoding:  string = "UTF-8"
  11.   xmlHeader: string = "<?xml version=\"1.0\" encoding=\"" & encoding & "\"?>"
  12.   root:      seq[string] = @["<root>","</root>"]
  13.   aTagDel:   seq[string]
  14.   destDir:   string
  15.   sourceDir: string = getAppDir()
  16.   destFile:  string = "all.xml"
  17.   opts:seq[string]
  18.   ARGS   = commandLineParams()
  19.   errors = newSeq[string]()
  20.   verbose:bool = false
  21.  
  22.  
  23. let doc =  """
  24. Joining XML files
  25.  
  26. Options:
  27.  -d --dest              Destination folder.
  28.  -n --name              Destination file name.
  29.  -s --source            Source folder.
  30.  -t --tag               Tag name (or a comma separated list) to remove
  31.  -x --header            XML-declaration line. By default:
  32.                         <?xml version=\"1.0\" encoding=\"UTF-8\"?>
  33.  -r --root              Root tag, which will combine the data of all files.
  34.                         By default: root
  35.  -v --verbose           Verbose mode
  36.  -h --help              Show this screen
  37.  
  38. Usage:
  39.  xmljoin --source=c:\test --dest=c:\test\new --name=new.xml
  40.  xmljoin -s=c:\test -d=c:\test\new
  41.  xmljoin -d=new -t=deleted,deleted1,deleted2 -r=main -v
  42.  xmljoin -d=new -r=main -x="<?xml version=\"1.0\" encoding=\"WINDOWS-1251\"?>"
  43.  xmljoin -d=new -r=main -x=WINDOWS-1251
  44.  
  45.  Specify an existing the destination directory;
  46.  source dir optional, by default - the program folder;
  47.  file name by default - all.xml
  48. """
  49.  
  50. proc help()=
  51.   styledEcho(
  52.     fgWhite,    "<xmljoin>\n",       resetStyle,
  53.     fgWhite,   "  <Author>",         resetStyle,
  54.     fgGreen,     "Gary Galler",      resetStyle,
  55.     fgWhite,   "</Author>\n",        resetStyle,
  56.     fgWhite,   "  <Copyright(C)>",   resetStyle,
  57.     fgGreen,     "Gary Galler, 2016.  All rights reserved", resetStyle,
  58.     fgWhite,   "</Copyright(C)>\n",  resetStyle,
  59.     fgWhite,   "  <Version>",        resetStyle,
  60.     fgGreen,     "1.0.0.3",          resetStyle,
  61.     fgWhite,   "</Version>\n",       resetStyle,
  62.     fgWhite,    "</xmljoin>\n",      resetStyle)
  63.   echo doc
  64.  
  65. #------------------------------------------------
  66. proc xmlDeclaration(header:string):string=
  67.   if not startsWith(header , "<?"):
  68.     result = xmlHeader.replace(encoding,header)
  69.   else:
  70.     result = header
  71.   return
  72.  
  73. proc validateParam(opts:seq[string]):auto=
  74.   if opts.len < 2:
  75.     raise newException(Exception,"Value of parameter [" & opts[0] & "] isn't specified")
  76.   return opts[1]
  77.  
  78. if ARGS.len==0: help(); quit()
  79.  
  80. for opt in ARGS:
  81.   opts = split(opt,{'='},1)
  82.  
  83.   case opts[0]
  84.     of "-s", "--source":  sourceDir = validateParam(opts)
  85.     of "-d", "--dest":    destDir   = validateParam(opts)
  86.     of "-n", "--name":    destFile  = validateParam(opts)
  87.     of "-t", "--tag":     aTagDel   = validateParam(opts).split(",")
  88.     of "-x", "--header":  xmlHeader = validateParam(opts).xmlDeclaration
  89.     of "-r", "--root":    root      = root.mapIt(it.replace("root",validateParam(opts)))
  90.     of "-v", "--verbose": verbose   = true
  91.     of "-h", "--help":    help(); quit()
  92.     else: raise newException(Exception,"Unknown argument [" & opts[0] & "]")
  93. #------------------------------------------------
  94. if destDir.isNil:
  95.   echo "Error: Specify the destination directory"; quit()
  96.  
  97. if not isAbsolute(destDir):
  98.   destDir = joinPath(getAppDir(),destDir)
  99.  
  100. if cmpIgnoreCase(destDir,sourceDir) == 0 :
  101.   echo "Error: Source directory and destination must be different"; quit()
  102.  
  103. for dir in [sourceDir,destDir]:
  104.   if not existsDir(dir):
  105.     raise newException(Exception,"The specified directory doesn't exist:\n" & dir)
  106.  
  107. setCurrentDir(sourceDir)
  108. #------------------------------------------------
  109. # удаление ноды по имени - возвращает индекс удаленного узла
  110. #------------------------------------------------
  111. proc deleteNodeByName(node:XmlNode,tagname:string):int=
  112.   var index = 0
  113.   for item in node.items:
  114.     if item.tag() == tagname:
  115.       node.delete(index);break
  116.     inc index
  117.   return index
  118. #------------------------------------------------
  119. # получаем кортеж с именем тега и секвенцией индексов
  120. #------------------------------------------------
  121. proc getNodeIndex(node:XmlNode,
  122.                   tagname:string
  123.                   ):tuple[tag:string,index:seq[int]]=
  124.   var num = 0
  125.   result.index=newSeq[int]()
  126.   for item in node.items:
  127.     if item.tag() == tagname:
  128.       result.tag = tagname
  129.       result.index.add(num)
  130.     inc num
  131.   return result
  132.  
  133. #------------------------------------------------
  134.  
  135. proc main()=
  136.   if not open(fHandle,joinPath(destDir,destFile),fmWrite):
  137.     raise newException(IOError,"Could not create file:" & destDir)
  138.   defer: fHandle.close()
  139.   fHandle.write(xmlHeader & "\c\L" & root[0] & "\c\L")
  140.  
  141.   for file in walkFiles("*.xml"):
  142.     let fullPath = getCurrentDir() / file
  143.     xml = loadXml(fullPath,errors)
  144.     if xml.isNil: continue
  145.     for node in xml.items:
  146.       if aTagDel.len > 0:
  147.         # цикл прохода по списку узлов для удаления
  148.         for str in aTagDel:
  149.           let data = getNodeIndex(node,str.strip)
  150.           for i in 0..<data.index.len:
  151.             let index = deleteNodeByName(node,data.tag)
  152.             echo "node:",node.tag(),"  ->delete:",data.tag,"[",index,"]"
  153.         # подробный режим
  154.         if verbose: echo node
  155.       # записываем содержимое узла в файл
  156.       fHandle.writeLine(node)
  157.     echo "=>Processed:", file
  158.  
  159.   fHandle.write(root[1])
  160.   #fHandle.close()
  161.   for err in errors:
  162.     styledEcho(fgRed,"=>Invalid XML:",resetStyle,fgWhite,err,resetStyle)
  163.  
  164.   echo "--------------------------------"
  165.   echo "sourceDir:",sourceDir
  166.   echo "destFile :",joinPath(destDir,destFile)
  167.   echo "--------------------------------"
  168.  
  169. # end proc
  170. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement