Issue
I am creating a script to automate and extract large amounts of text files; Currently, my problem is to get target id from .html files, example below:
\ \ <body id="some_id" class="calibre2">
what of my script function is to get "some_id" and check it is valid(ID is not allowed to start with a number) otherwise fix this id in .html file and other related files(toc.ncx, content.opf etc), my main used command is sed(but I think my method is cumbersome), the shell is below:
#!/bin/bash
for var in ./*
do
if [[ $var =~ .*.html ]]
then
if grep -q -E '<body id="[0-9]+' $var
then
ID="$(sed -n -E 's/\ \ <body id="[0-9]+(.*?)"\ .*/\1/gp' $var)"
echo $ID
sed -i -E 's/<body\ id="([0-9]+)/<body id="id\1/g' $var
sed -i -E "s/$ID/id$ID/g" ./../toc.ncx
echo $var
fi
fi
done
that means I don't know the ID of html, but I know the rule of ID, example below:
\ \ <body id="123char" class="calibre2">
"123char" is invalid, because ID is not allowed to start with a number, so I need to fix the ID with appending prefix characters, like "idchar", so html become below:
\ \ <body id="idchar" class="calibre2">
At the same time I need to update other file's id(change "123char" to "idchar"), like .ncx file
<content src="Text/xxx1.html#123char"/>
<!--need changes id as follow-->
<content src="Text/xxx1.html#idchar"/>
PS: as showed above, this shell is aimed at fixing .epub fix that can't pass epub validator, many e-book converters from mobi to epub have this type of bug(calibre, convertio...etc)
Solution
This has been repeated here countless times already; it's a really bad idea to parse/edit HTML with regex! An HTML parser like xidel would be better suited. In fact, with its integrated EXPath File module one single call could be all you need:
$ xidel -se '
for $x in file:list(.,false(),"*.html")
where matches(doc($x)//body/@id,"^\d")
return
file:write(
$x,
x:replace-nodes(
doc($x)//body/@id,
function($x){attribute {name($x)} {replace($x,"^\d+","id")}}
),
{"method":"html","indent":true()}
)
'
file:list(.,false(),"*.html")
returns all HTML-files in the current dir.matches(doc($x)//body/@id,"^\d")
restricts that to only those HTML-files with anid
attribute's value that starts with a number.x:replace-nodes( [...] )
replaces the number of that value with the string "id".file:write( [...] )
replaces the original HTML-file.
Answered By - Reino Answer Checked By - Marie Seifert (WPSolving Admin)