Wikia

Vim Tips Wiki

Changes: Pretty-formatting XML

Edit

Back to page

(Replaced content with "<?xml version="1.0" encoding="utf-8" ?><user_get_response><user><buyer_credit><good_num>0</good_num><level>0</level><score>0</score><total_num>0</total_num></buyer_credit>...")
Line 1: Line 1:
{{review}}
+
<?xml version="1.0" encoding="utf-8" ?><user_get_response><user><buyer_credit><good_num>0</good_num><level>0</level><score>0</score><total_num>0</total_num></buyer_credit><created>2012-05-11 17:23:03</created><last_visit>2012-05-11 17:23:03</last_visit><location></location><nick>liujinxiao2012</nick><seller_credit><good_num>0</good_num><level>0</level><score>0</score><total_num>0</total_num></seller_credit><sex>m</sex><type>C</type></user></user_get_response><!--top163184.cm3-->
{{TipImported
 
|id=1366
 
|previous=1363
 
|next=1369
 
|created=2006
 
|complexity=intermediate
 
|author=Cory
 
|version=6.0
 
|rating=8/10
 
|category1=XML
 
|category2=
 
}}
 
Add this to your vimrc so you can type <code>:PrettyXML</code> and automatically pretty-format XML. Requires the command 'xmllint' in your PATH.
 
 
Note that this ignores significant whitespace! The result will be more readable, but it may not be semantically identical. I use this to read badly-formatted XML documents, not to save them.
 
<pre>
 
function! DoPrettyXML()
 
" save the filetype so we can restore it later
 
let l:origft = &ft
 
set ft=
 
" delete the xml header if it exists. This will
 
" permit us to surround the document with fake tags
 
" without creating invalid xml.
 
1s/<?xml .*?>//e
 
" insert fake tags around the entire document.
 
" This will permit us to pretty-format excerpts of
 
" XML that may contain multiple top-level elements.
 
0put ='<PrettyXML>'
 
$put ='</PrettyXML>'
 
silent %!xmllint --format -
 
" xmllint will insert an <?xml?> header. it's easy enough to delete
 
" if you don't want it.
 
" delete the fake tags
 
2d
 
$d
 
" restore the 'normal' indentation, which is one extra level
 
" too deep due to the extra tags we wrapped around the document.
 
silent %<
 
" back to home
 
1
 
" restore the filetype
 
exe "set ft=" . l:origft
 
endfunction
 
command! PrettyXML call DoPrettyXML()
 
</pre>
 
 
==Comments==
 
I tried it on [http://www.hab.de/bibliothek/wdb/emblematica/emblemsample.xml emblemsample.xml]. Buffer was empty after that.
 
:You need xmllint in your PATH (the buffer is replaced with the output from trying to run xmllint).
 
 
----
 
The following is my solution. gvim 7.0 on Windows XP. Ruby must be installed.
 
<pre>
 
# download xmlformat
 
# copy xmlformat.rb to a folder, d:\bin for exmaple
 
# open the xml document to be formated in Vim
 
# type command
 
:% !ruby d:\bin\xmlformat.rb
 
</pre>
 
 
----
 
From [[VimTip551|Automatically indent an XML file using XSLT]] comes this solution, which I prefer:
 
<pre>
 
:%s/></>\r</g
 
:0
 
=:$
 
</pre>
 
 
----
 
Hi, when I run this script I always get:
 
<pre>
 
Error detected while processing function DoPrettyXML:
 
line 7:
 
</pre>
 
 
:That is because line 7 (<code>1s/<?xml .*?>//</code>) tried to do a substitute in line 1, and gave an error because there was no matching text in your file. I added the 'e' flag so errors will be ignored. I also did some other style tweaks. Please reply with whether it works. --[[User:JohnBeckett|JohnBeckett]] 01:19, 8 October 2008 (UTC)
 
 
----
 
 
Here is a slightly less than elegant solution to cleanup XML that is all on one line. This does not require XSLT or any special plugins, just some regular expressions.
 
 
I put this in my _vimrc
 
 
<pre>
 
map <F5> :%s/<\([^>]\)*>/\r&\r/g<enter>:g/^$/d<enter>vat=
 
map <F6> vatJxvito<right><left>x
 
map <F7> /\v^\s*([a-zA-Z\-0-9\$])<enter>qm<F6>nq@q1000@@:1<enter>
 
</pre>
 
 
When I open an XML, I hit F5... this breaks it all into individual lines. Hit F7, if you want the XML node and content to be on the same line.
 
 
----
 
When using Unicode document, xmllint converts all characters to xml entities such as &#000;
 
the solution is to add encoding to the xmllint line, like this:
 
<pre>
 
silent %!xmllint --encode UTF-8 --format -
 
</pre>
 
but there may be some more generic way (to detect the encoding and set accordingly)
 
 
----
 
Based on the solution suggested in this tip, I created the following one, that provides some improvements:
 
 
# Open an XML file and type <leader>x in normal mode; the entire file will get formatted.
 
# Enter visual mode, select some (valid by itself!) XML code and also press <leader>x, only the selected text will be processed.
 
 
Just put the following in your vimrc:
 
 
<pre>
 
" XML formatter
 
function! DoFormatXML() range
 
" Save the file type
 
let l:origft = &ft
 
 
" Clean the file type
 
set ft=
 
 
" Add fake initial tag (so we can process multiple top-level elements)
 
exe ":let l:beforeFirstLine=" . a:firstline . "-1"
 
if l:beforeFirstLine < 0
 
let l:beforeFirstLine=0
 
endif
 
exe a:lastline . "put ='</PrettyXML>'"
 
exe l:beforeFirstLine . "put ='<PrettyXML>'"
 
exe ":let l:newLastLine=" . a:lastline . "+2"
 
if l:newLastLine > line('$')
 
let l:newLastLine=line('$')
 
endif
 
 
" Remove XML header
 
exe ":" . a:firstline . "," . a:lastline . "s/<\?xml\\_.*\?>\\_s*//e"
 
 
" Recalculate last line of the edited code
 
let l:newLastLine=search('</PrettyXML>')
 
 
" Execute external formatter
 
exe ":silent " . a:firstline . "," . l:newLastLine . "!xmllint --noblanks --format --recover -"
 
 
" Recalculate first and last lines of the edited code
 
let l:newFirstLine=search('<PrettyXML>')
 
let l:newLastLine=search('</PrettyXML>')
 
 
" Get inner range
 
let l:innerFirstLine=l:newFirstLine+1
 
let l:innerLastLine=l:newLastLine-1
 
 
" Remove extra unnecessary indentation
 
exe ":silent " . l:innerFirstLine . "," . l:innerLastLine "s/^ //e"
 
 
" Remove fake tag
 
exe l:newLastLine . "d"
 
exe l:newFirstLine . "d"
 
 
" Put the cursor at the first line of the edited code
 
exe ":" . l:newFirstLine
 
 
" Restore the file type
 
exe "set ft=" . l:origft
 
endfunction
 
command! -range=% FormatXML <line1>,<line2>call DoFormatXML()
 
 
nmap <silent> <leader>x :%FormatXML<CR>
 
vmap <silent> <leader>x :FormatXML<CR>
 
</pre>
 
 
Thanks a lot to the original writer of this tip! :)
 
I hope you fine this useful! Cheers, [[User:Gsimone|Gsimone]] ([[User talk:Gsimone|talk]]) 22:17, December 19, 2012 (UTC).
 

Revision as of 07:29, March 8, 2013

<?xml version="1.0" encoding="utf-8" ?><user_get_response><user><buyer_credit><good_num>0</good_num><level>0</level><score>0</score><total_num>0</total_num></buyer_credit><created>2012-05-11 17:23:03</created><last_visit>2012-05-11 17:23:03</last_visit><location></location><nick>liujinxiao2012</nick><seller_credit><good_num>0</good_num><level>0</level><score>0</score><total_num>0</total_num></seller_credit><sex>m</sex><type>C</type></user></user_get_response>

Around Wikia's network

Random Wiki