Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- {.boundChecks: on.}
- import xmlparser,xmltree
- import os,strutils,sequtils
- import terminal
- #------------------------------------------------
- var
- xml: XmlNode
- fHandle: File
- encoding: string = "UTF-8"
- xmlHeader: string = "<?xml version=\"1.0\" encoding=\"" & encoding & "\"?>"
- root: seq[string] = @["<root>","</root>"]
- aTagDel: seq[string]
- destDir: string
- sourceDir: string = getAppDir()
- destFile: string = "all.xml"
- opts:seq[string]
- ARGS = commandLineParams()
- errors = newSeq[string]()
- verbose:bool = false
- let doc = """
- Joining XML files
- Options:
- -d --dest Destination folder.
- -n --name Destination file name.
- -s --source Source folder.
- -t --tag Tag name (or a comma separated list) to remove
- -x --header XML-declaration line. By default:
- <?xml version=\"1.0\" encoding=\"UTF-8\"?>
- -r --root Root tag, which will combine the data of all files.
- By default: root
- -v --verbose Verbose mode
- -h --help Show this screen
- Usage:
- xmljoin --source=c:\test --dest=c:\test\new --name=new.xml
- xmljoin -s=c:\test -d=c:\test\new
- xmljoin -d=new -t=deleted,deleted1,deleted2 -r=main -v
- xmljoin -d=new -r=main -x="<?xml version=\"1.0\" encoding=\"WINDOWS-1251\"?>"
- xmljoin -d=new -r=main -x=WINDOWS-1251
- Specify an existing the destination directory;
- source dir optional, by default - the program folder;
- file name by default - all.xml
- """
- proc help()=
- styledEcho(
- fgWhite, "<xmljoin>\n", resetStyle,
- fgWhite, " <Author>", resetStyle,
- fgGreen, "Gary Galler", resetStyle,
- fgWhite, "</Author>\n", resetStyle,
- fgWhite, " <Copyright(C)>", resetStyle,
- fgGreen, "Gary Galler, 2016. All rights reserved", resetStyle,
- fgWhite, "</Copyright(C)>\n", resetStyle,
- fgWhite, " <Version>", resetStyle,
- fgGreen, "1.0.0.3", resetStyle,
- fgWhite, "</Version>\n", resetStyle,
- fgWhite, "</xmljoin>\n", resetStyle)
- echo doc
- #------------------------------------------------
- proc xmlDeclaration(header:string):string=
- if not startsWith(header , "<?"):
- result = xmlHeader.replace(encoding,header)
- else:
- result = header
- return
- proc validateParam(opts:seq[string]):auto=
- if opts.len < 2:
- raise newException(Exception,"Value of parameter [" & opts[0] & "] isn't specified")
- return opts[1]
- if ARGS.len==0: help(); quit()
- for opt in ARGS:
- opts = split(opt,{'='},1)
- case opts[0]
- of "-s", "--source": sourceDir = validateParam(opts)
- of "-d", "--dest": destDir = validateParam(opts)
- of "-n", "--name": destFile = validateParam(opts)
- of "-t", "--tag": aTagDel = validateParam(opts).split(",")
- of "-x", "--header": xmlHeader = validateParam(opts).xmlDeclaration
- of "-r", "--root": root = root.mapIt(it.replace("root",validateParam(opts)))
- of "-v", "--verbose": verbose = true
- of "-h", "--help": help(); quit()
- else: raise newException(Exception,"Unknown argument [" & opts[0] & "]")
- #------------------------------------------------
- if destDir.isNil:
- echo "Error: Specify the destination directory"; quit()
- if not isAbsolute(destDir):
- destDir = joinPath(getAppDir(),destDir)
- if cmpIgnoreCase(destDir,sourceDir) == 0 :
- echo "Error: Source directory and destination must be different"; quit()
- for dir in [sourceDir,destDir]:
- if not existsDir(dir):
- raise newException(Exception,"The specified directory doesn't exist:\n" & dir)
- setCurrentDir(sourceDir)
- #------------------------------------------------
- # удаление ноды по имени - возвращает индекс удаленного узла
- #------------------------------------------------
- proc deleteNodeByName(node:XmlNode,tagname:string):int=
- var index = 0
- for item in node.items:
- if item.tag() == tagname:
- node.delete(index);break
- inc index
- return index
- #------------------------------------------------
- # получаем кортеж с именем тега и секвенцией индексов
- #------------------------------------------------
- proc getNodeIndex(node:XmlNode,
- tagname:string
- ):tuple[tag:string,index:seq[int]]=
- var num = 0
- result.index=newSeq[int]()
- for item in node.items:
- if item.tag() == tagname:
- result.tag = tagname
- result.index.add(num)
- inc num
- return result
- #------------------------------------------------
- proc main()=
- if not open(fHandle,joinPath(destDir,destFile),fmWrite):
- raise newException(IOError,"Could not create file:" & destDir)
- defer: fHandle.close()
- fHandle.write(xmlHeader & "\c\L" & root[0] & "\c\L")
- for file in walkFiles("*.xml"):
- let fullPath = getCurrentDir() / file
- xml = loadXml(fullPath,errors)
- if xml.isNil: continue
- for node in xml.items:
- if aTagDel.len > 0:
- # цикл прохода по списку узлов для удаления
- for str in aTagDel:
- let data = getNodeIndex(node,str.strip)
- for i in 0..<data.index.len:
- let index = deleteNodeByName(node,data.tag)
- echo "node:",node.tag()," ->delete:",data.tag,"[",index,"]"
- # подробный режим
- if verbose: echo node
- # записываем содержимое узла в файл
- fHandle.writeLine(node)
- echo "=>Processed:", file
- fHandle.write(root[1])
- #fHandle.close()
- for err in errors:
- styledEcho(fgRed,"=>Invalid XML:",resetStyle,fgWhite,err,resetStyle)
- echo "--------------------------------"
- echo "sourceDir:",sourceDir
- echo "destFile :",joinPath(destDir,destFile)
- echo "--------------------------------"
- # end proc
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement