Vim as XML Editor: Setup
Again, this is just one way of setting things up. TMTOWTDI ;) Your local environment is likely to be different, as well as your preferences, and the tools evolve. I'll give a short overview of what I use; please refer to the documentation of the respective tool for instructions on how to best set things up.
If you experience problems with any of the tools featured below please file bug reports directly to the respective project.
Linux
~/.bashrc
set -o vi
export EDITOR='/usr/bin/vim'
PATH="${HOME}/data/commands:${PATH}"
export PATH
PS1='\u \w \$ '
XML_CATALOG_FILES="${HOME}/data/conf/xml/catalog /etc/xml/catalog"
export XML_CATALOG_FILES
Often it helps to do source .bashrc after having modified .bashrc and after having created new command scripts.
Windows
When creating batch files on Windows (file name suffix .bat) don't forget to make sure that the file format is set correctly. You can check it with :set fileformat? and set it with :set fileformat=dos.
vimrc
" Windows: $VIM/_vimrc (original)
" *n*x : ~/.vimrc
" pinkjuice.com/vim/vimrc.txt
" for more info check
" pinkjuice.com/vim/
" regarding XML related stuff check
" pinkjuice.com/howto/vimxml/
" The following works for me with Vim 6.2 on Windows
" (most stuff also works on Linux),
" but I don't recommend to blindly copy and use it.
" (check the respective documentation)
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" general
set nocompatible
highlight Normal guifg=Black guibg=#ffefd5
set formatoptions=t
set textwidth=70
set encoding=utf-8
set termencoding=latin1
set fileformat=unix
"set guifont=courier_new:h10
set guifont=Courier\ New:h10,Courier,Lucida\ Console,Letter\ Gothic,
\Arial\ Alternative,Bitstream\ Vera\ Sans\ Mono,OCR\ A\ Extended
set nowrap
set shiftwidth=2
set visualbell
set noerrorbells
set number
set autoindent
set ruler
set expandtab
set whichwrap=<,>,h,l
set guioptions=bgmrL
set backspace=2
set history=50
set backup
set wildmenu
set nrformats=
set foldlevelstart=99
if has("unix")
set shcf=-ic
endif
let mapleader = ","
let $ADDED = '~/.vim/added/'
if has("win32")
let $ADDED = $VIM.'/added/'
endif
map <Leader>cd :exe 'cd ' . expand ("%:p:h")<CR>
nmap <F1> :w<CR>
imap <F1> <ESC>:w<CR>a
map <F8> gg"+yG
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Installed
" www.vim.org/scripts/script.php?script_id=301
" $ADDED/xml.vim
" www.vim.org/scripts/script.php?script_id=39
" copied macros/matchit.vim to plugin/
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" XML
map <Leader>x :set filetype=xml<CR>
\:source $VIMRUNTIME/syntax/xml.vim<CR>
\:set foldmethod=syntax<CR>
\:source $VIMRUNTIME/syntax/syntax.vim<CR>
\:colors peachpuff<CR>
\:source $ADDED/xml.vim<CR>
\:iunmap <buffer> <Leader>.<CR>
\:iunmap <buffer> <Leader>><CR>
\:inoremap \> ><CR>
\:echo "XML mode is on"<CR>
" no imaps for <Leader>
"\:inoremap \. ><CR>
" catalog should be set up
nmap <Leader>l <Leader>cd:%w !xmllint --valid --noout -<CR>
nmap <Leader>r <Leader>cd:%w !rxp -V -N -s -x<CR>
nmap <Leader>d4 :%w !xmllint --dtdvalid
\ "https://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
\ --noout -<CR>
vmap <Leader>px !xmllint --format -<CR>
nmap <Leader>px !!xmllint --format -<CR>
nmap <Leader>pxa :%!xmllint --format -<CR>
nmap <Leader>i :%!xsltlint<CR>
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Ruby
" check
" www.rubygarden.org/ruby?VimExtensions
let mapleader = ","
and
nmap <Leader>l <Leader>cd:%w !xmllint --valid --noout -<CR>
which means that whenever I want xmllint to validate the buffer
I do
,
l
.
Jump
around the buffer with
%
,
eg between opening and closing angle brackets of XML tags
and between opening and closing tags
when XML syntax recognition is turned on.
Devin Weaver's xmledit provides some editing features such as closing and deleting tags, and wrapping strings in tag pairs.
let $ADDED = '~/.vim/added/'
if has("win32")
let $ADDED = $VIM.'/added/'
endif
and
map <Leader>x :set filetype=xml<CR>
\:source $VIMRUNTIME/syntax/xml.vim<CR>
\:set foldmethod=syntax<CR>
\:source $VIMRUNTIME/syntax/syntax.vim<CR>
\:colors peachpuff<CR>
\:source $ADDED/xml.vim<CR>
so I can turn on XML editing mode whenever I want.
I don't want it to be turned on automatically because
- when I open a large file it would slow down editing
- sometimes I have files with mixed syntax (eg XML snippets in a text file)
- I prefer to be independent from filename suffixes
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
this DTD needs to get loaded.
Normally it gets downloaded from the web,
which can take a while with large schemas such as DocBook.
Changing the URL
to a local path each time is tedious,
especially if there are many documents.
Convenient and fast offline validation
can be achieved though
setting up a catalog system.
When using xmllint
,
this means nothing more than creating a simple catalog file,
and making its path available to xmllint
.
<
public
publicId
=
"
-//W3C//DTD XHTML 1.0 Strict//EN
"
uri
=
"
xhtml/1_0/strict/dtd/xhtml1-strict.dtd
"
/
>
Any XML tool which supports
OASIS
XML Catalogs
(OASIS
Catalogs specification)
can now see if there is a local copy
of the corresponding DTD
available.
It simply grabs the FPI
from the document, and looks it up in the catalog.
<
system
systemId
=
"
https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd
"
uri
=
"
xhtml/1_0/strict/dtd/xhtml1-strict.dtd
"
/
>
This is useful in cases where there is no FPI
available.
rxp
, xmllint
, and
xsltproc
support multiple catalogs.
In my .bashrc I have
XML_CATALOG_FILES="${HOME}/data/conf/xml/catalog /etc/xml/catalog"
export XML_CATALOG_FILES
and my catalog looks like this:
~/data/conf/xml/catalog
<?
xml
version
=
"
1.0
"
?>
<!DOCTYPE catalog
PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN"
"https://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<
catalog
xmlns
=
"
urn:oasis:names:tc:entity:xmlns:xml:catalog
"
>
<
group
prefer
=
"
public
"
xml:base
=
"
file:///home/tobi/bulk/xml/schemas/
"
>
<
public
publicId
=
"
-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN
"
uri
=
"
oasis_catalogs/1_0/dtd/catalog.dtd
"
/
>
<
system
systemId
=
"
https://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd
"
uri
=
"
oasis_catalogs/1_0/dtd/catalog.dtd
"
/
>
<
public
publicId
=
"
-//W3C//DTD XHTML 1.0 Strict//EN
"
uri
=
"
xhtml/1_0/strict/dtd/xhtml1-strict.dtd
"
/
>
<
system
systemId
=
"
https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd
"
uri
=
"
xhtml/1_0/strict/dtd/xhtml1-strict.dtd
"
/
>
<
public
publicId
=
"
-//OASIS//DTD DocBook XML V4.2//EN
"
uri
=
"
docbook/4_2/dtd/docbookx.dtd
"
/
>
<
system
systemId
=
"
https://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd
"
uri
=
"
docbook/4_2/dtd/docbookx.dtd
"
/
>
<
public
publicId
=
"
-//W3C//DTD SVG 1.0//EN
"
uri
=
"
svg/1_0/dtd/svg10.dtd
"
/
>
<
system
systemId
=
"
https://www.w3.org/TR/SVG10/DTD/svg10.dtd
"
uri
=
"
svg/1_0/dtd/svg10.dtd
"
/
>
<
system
systemId
=
"
https://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd
"
uri
=
"
svg/1_0/dtd/svg10.dtd
"
/
>
<
public
publicId
=
"
-//W3C//DTD SVG 1.1//EN
"
uri
=
"
svg/1_1/dtd/svg11-flat.dtd
"
/
>
<
system
systemId
=
"
https://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd
"
uri
=
"
svg/1_1/dtd/svg11-flat.dtd
"
/
>
<
system
systemId
=
"
https://www.w3.org/Graphics/SVG/1.1/DTD/svg11-flat.dtd
"
uri
=
"
svg/1_1/dtd/svg11-flat.dtd
"
/
>
<
/
group
>
<
/
catalog
>
xmllint
,
but also by the resolvers of some other tools such as validators
and
XSLT processors.
xmllint is part of libxml, the XML C library for GNOME. It's lightning fast and can be used for validation and pretty printing.
On Linux
Most of the following should work analogously on other Unix-like OSs such as BSD.
xmllint
might already be
installed on your system.
In order to not risk any conflicts
I installed the latest versions under my home directory using the
following shell script:
install_libxml
#!/bin/bash -x
# or
#!/usr/bin/env bash
# todo:
#
# refactor, wrap a lot of redundant code in functions
#
# pass --disable-shared to configure?
# or --enable-static, or both? do
# tobi ~/del $ grep AttributeError \
# libxml_cvs_installation.log | wc -l
# this is just an example you could use as basis for your script
# (do not run it without having revised and adjusted it)
# usage: (be online)
# (remove existing identical/redundant commands and logs,
# and empty compilation, (download,) and run directories)
# if not CVS then set versions below
# [as user do:]
# $ cd del
# $ ~/data/run/install_libxml --cvs \
# 2>&1 | tee libxml_cvs_installation.log
# (or &> libxml_cvs_installation.log ?)
# (then run without [...]cvs:
# $ ~/data/run/install_libxml 2>&1 | tee libxml_installation.log
# )
# optionally monitor with lines like
# $ tail -f \
# ~/del/compile_libxml/libxml2-2.6.9/my_xml_make_errors.log
# if the installation succeeded,
# set latest stable versions as defaults
# cd
# cp -i data/commands/xmllint_2.6.9 data/commands/xmllint
# cp -i data/commands/xsltproc_1.1.6 data/commands/xsltproc
# [not necessarily required:]
# source .bashrc
# xmllint --version
# xsltproc --version
# this script is install_libxml
# Various lines were contributed by William M. Brack; thanks!
# zlib-devel should be available among other things,
# see libxml2-[version]/INSTALL
my_home=/home/tobi
if [ $HOME != $my_home ]; then
exit
fi
if [ `whoami` != 'tobi' ]; then
exit
fi
cd ${HOME}/del
case $# in
0) ;;
*)
for a do
case $a in
-c|--cvs)
cvs=true;;
*)
echo "unexpected arg $a"
exit;;
esac
done
esac
# set:
# check for latest versions at ftp://xmlsoft.org/
if [ $cvs ]; then
ver_libxml='cvs'
ver_libxslt='cvs'
else
ver_libxml=2.6.9
ver_libxslt=1.1.6
fi
uname -a
tools="
gcc
make
automake
install
"
for tool in $tools ; do
$tool --version
done
/lib/ld-linux.so.2 /lib/libc.so.6 | head -1
# does it make any sense to scan the files?
av_command="antivir -rs -z"
compile=${HOME}/del/compile_libxml
run_libxml_top=${HOME}/bulk/run/libxml
run_libxml=${run_libxml_top}/${ver_libxml}
run_libxslt_top=${HOME}/bulk/run/libxslt
run_libxslt=${run_libxslt_top}/${ver_libxslt}
if [ ! -d $compile ]; then
mkdir $compile
fi
if [ ! -d $compile/download ]; then
mkdir ${compile}/download
fi
if [ -d $run_libxml ]; then
echo ${run_libxml}' exists, exiting'
exit
else
if [ ! -d $run_libxml_top ]; then
mkdir $run_libxml_top
fi
if [ ! -d $run_libxml ]; then
mkdir $run_libxml
fi
fi
if [ -d $run_libxslt ]; then
echo ${run_libxslt}' exists, exiting'
exit
else
if [ ! -d $run_libxslt_top ]; then
mkdir $run_libxslt_top
fi
if [ ! -d $run_libxslt ]; then
mkdir $run_libxslt
fi
fi
cd $compile
if [ $cvs ]; then
url_libxml='ftp://xmlsoft.org/libxml2-cvs-snapshot.tar.gz'
url_libxslt='ftp://xmlsoft.org/libxslt-cvs-snapshot.tar.gz'
else
url_libxml="ftp://xmlsoft.org/libxml2-${ver_libxml}.tar.gz"
url_libxslt="ftp://xmlsoft.org/libxslt-${ver_libxslt}.tar.gz"
fi
file_libxml=`basename ${url_libxml}`
file_libxslt=`basename ${url_libxslt}`
if [ ! -f download/$file_libxml ]; then
cd download
wget $url_libxml
# should: exit if download didn't succeed
if [ ! -e $file_libxml ]; then
exit
fi
$av_command $file_libxml
if [ $? != 0 ]; then
exit
fi
cd ../
fi
if [ ! -f download/$file_libxslt ]; then
cd download
wget $url_libxslt
# should: exit if download didn't succeed
if [ ! -e $file_libxslt ]; then
exit
fi
$av_command $file_libxslt
if [ $? != 0 ]; then
exit
fi
cd ../
fi
libxml2_cvs_dir_name=libxml2-cvs
libxslt_cvs_dir_name=libxslt-cvs
if [ $cvs ]; then
mkdir $libxml2_cvs_dir_name && cd $libxml2_cvs_dir_name
tar -xzf ../download/${file_libxml}
cd ../
# toplevel_xml_dir="${compile}/${libxml2_cvs_dir_name}/*/"
toplevel_xml_dir_parent="${compile}/${libxml2_cvs_dir_name}"
toplevel_xml_dir="${toplevel_xml_dir_parent}/$(ls $toplevel_xml_dir_parent)"
mkdir $libxslt_cvs_dir_name && cd $libxslt_cvs_dir_name
tar -xzf ../download/${file_libxslt}
cd ../
# toplevel_xslt_dir="${compile}/${libxslt_cvs_dir_name}/*/"
toplevel_xslt_dir_parent="${compile}/${libxslt_cvs_dir_name}"
toplevel_xslt_dir="${toplevel_xslt_dir_parent}/$(ls $toplevel_xslt_dir_parent)"
else
toplevel_xml_dir="${compile}/libxml2-${ver_libxml}"
toplevel_xslt_dir="${compile}/libxslt-${ver_libxslt}"
tar -xzf download/${file_libxml}
tar -xzf download/${file_libxslt}
fi
if [ $cvs ]; then
# configure='autogen.sh'
configure='configure'
# --enable-static --disable-shared ?
else
configure='configure'
# --enable-static --disable-shared ?
fi
cd $toplevel_xml_dir
if [ $cvs ] && [ -f Makefile ]; then
make distclean
fi
./${configure} --prefix=${run_libxml} \
2>&1 | tee my_xml_config.log
# make CFLAGS="-g -O2 -static" \
make \
2>my_xml_make_errors.log | tee my_xml_make.log
make tests 2>&1 | tee my_xml_tests.log
make install
cd $toplevel_xslt_dir
if [ $cvs ] && [ -f Makefile ]; then
make distclean
fi
./${configure} --prefix=${run_libxslt} \
--with-libxml-src=${toplevel_xml_dir} \
2>&1 | tee my_xslt_config.log
# make CFLAGS="-g -O2 -static" \
make \
2>my_xslt_make_errors.log | tee my_xslt_make.log
make tests 2>&1 | tee my_xslt_tests.log
make install
command_xmllint=${HOME}/data/commands/xmllint_${ver_libxml}
command_xsltproc=${HOME}/data/commands/xsltproc_${ver_libxslt}
if [ ! -f $command_xmllint ]; then
cat > $command_xmllint << EOF
#!/usr/bin/env sh
# may get overwritten
${run_libxml}/bin/xmllint "\$@"
EOF
chmod 700 $command_xmllint
$command_xmllint --version
fi
if [ ! -f $command_xsltproc ]; then
cat > $command_xsltproc << EOF
#!/usr/bin/env sh
# may get overwritten
${run_libxslt}/bin/xsltproc "\$@"
EOF
chmod 700 $command_xsltproc
$command_xsltproc --version
fi
# email my_*.log files?
# below tgz plus
# del/libxml_cvs_installation.log
# and this script
cd $compile
tar -czf tobilogs${ver_libxml}.tgz \
-C $toplevel_xml_dir \
my_xml_config.log my_xml_make.log \
my_xml_make_errors.log my_xml_tests.log \
-C $toplevel_xslt_dir \
my_xslt_config.log my_xslt_make.log \
my_xslt_make_errors.log my_xslt_tests.log
:%w !xmllint --noout --dtdvalid /path/to/
xhtml1-strict.dtd -
$ echo $PATH
might already include ~/bin/
so if you don't want to
add a new directory
to the system path you can put your calls
into /your/home/
bin/.
~/bin/xmlval
#!/usr/bin/env bash
XML_CATALOG_FILES=/path/to/
catalog
export XML_CATALOG_FILES
xmllint --valid --noout "$@"
$ chmod 700 ~/bin/xmlval
If you are in a bash shell,
$ xmlval --version
should return the version of xmllint.
xmlval
you need to ask the shell to search the path
again.
If
$ echo $SHELL
returns csh or tcsh
you can try
$ set path=($path)
and test it with
$ xmlval --version
:%w !xmlval -
to validate documents which have doctype declarations.
xmllint
directly, and set the environment variable
XML_CATALOG_FILES in the rc file of the shell.$ vim .cshrc
then append
setenv XML_CATALOG_FILES "/path/to/
catalog"
and do
$ source .cshrc
Now
:%w !xmllint --valid --noout -
should work fast and offline if there's a doctype declaration and if
the catalog contains a link to a corresponding schema.
XML_CATALOG_FILES="/path/to/
catalog"
export XML_CATALOG_FILES
then do
$ source .bashrc
and test it with
$ echo $XML_CATALOG_FILES
:%w !xmllint --valid --noout -
in Vim.
On Windows
version
.win32.zip ,
create the following batch file calling xmllint
and put it in a directory which you added to the
system path;
mine is called
calls\
and I use it for most tools.
xmllint.bat
@echo off
set XML_CATALOG_FILES=/path/to/
catalog
"\path\to\
libxml2-version
.win32\bin\xmllint" %1 %2 %3 %4 %5
xmllint.bat (Windows 95/98/ME)
@echo off
command.com /e:3000 /c xmllint_raw %1 %2 %3 %4 %5
cmd.exe /c
but it shouldn't be necessary.
version
.win32\bin\
to the system path
but you'd have to restart Windows,
and if you do this for all the directories
of the tools the path can get too long.
I don't recommend putting the files into Windows directories such as
C:\WINDOWS\
since this can cause conflicts.
xmllint
from Vim's
command line and ask it to validate some XML.
Below are some tiny skeletons
you can use.
SVG:
<?
xml
version
=
"
1.0
"
encoding
=
"
UTF-8
"
standalone
=
"
no
"
?>
<!DOCTYPE svg
PUBLIC "-//W3C//DTD SVG 1.0//EN"
"https://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<
svg
>
<
/
svg
>
XHTML:
<?
xml
version
=
"
1.0
"
encoding
=
"
UTF-8
"
?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<
html
xmlns
=
"
http://www.w3.org/1999/xhtml
"
xml:lang
=
"
en
"
lang
=
"
en
"
>
<
head
>
<
title
>
<
/
title
>
<
/
head
>
<
body
>
<
h1
>
<
/
h1
>
<
div
>
<
/
div
>
<
/
body
>
<
/
html
>
:!xmllint --valid --noout %
The
--valid option tells
xmllint
to validate the doc, and the other arguments
should be self-explanatory.
Find more command examples in chapter Tasks.
You can never have enough validators :) The error messages vary in usefulness, and some errors aren't caught when using only one validator. RXP is developed by Richard Tobin who is one of the editors of Namespaces in XML 1.1.
On Linux
make
and wget
is omitted.
$ cd del
$ mkdir compile_rxp && cd compile_rxp
$ wget ftp://ftp.cogsci.ed.ac.uk/pub/richard/rxp-1.4.0pre10.tar.gz
$ tar xzf rxp-1.4.0pre10.tar.gz
$ cd rxp-1.4.0pre10
$ make
$ mkdir ~/bulk/run/rxp
$ mkdir ~/bulk/run/rxp/1_4_0_pre_10
$ ls | egrep "^[^\.]+$" | \
> xargs cp --target-directory=$HOME/bulk/run/rxp/1_4_0_pre_10
$ ed
a
#!/usr/bin/env sh
${HOME}/bulk/run/rxp/1_4_0_pre_10/rxp "$@"
.
w /home/tobi/data/commands/rxp
61
q
$ chmod 700 ~/data/commands/rxp
$ source ~/.bashrc
$ rxp -v
RXP 1.4.0pre10 Copyright Richard Tobin,
LTG, HCRC, University of Edinburgh
<foo />
Input encoding UTF-8, output encoding UTF-8
<foo/>
$
If you follow the steps, don't type the > after
the line ending with \,
and type
[ctrl
-d
]
to end input to the
rxp -v
command.
On Windows
rxp.bat
@echo off
set XML_CATALOG_FILES=file:///drive
:/path/to/
catalog
\path\to\
rxpversion
.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
rxp_raw.bat (Win9*)
@echo off
set XML_CATALOG_FILES=file:///drive
:/path/to/
catalog
\path\to\
rxpversion
.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
rxp.bat (Win9*)
@echo off
command.com /e:3000 /c rxp_raw %1 %2 %3 %4 %5 %6 %7 %8 %9
rxpval.bat
@echo off
rxp -V -N -s -x %1 %2 %3 %4 %5 %6 %7 %8 %9