Code permettant l'indentation d'un fichier HTML 5 afin d'en rendre la lecture analytique plus aisée.
N'ayant pas trouvé sur le Net de RegEX concluant, les uns ou les autres échouant toujours à un moment ou à un autre, j'ai donc dû élaborer mon propre ReGex qui, je crois après des tests sur de nombreuses pages HTML, fonctionne parfaitement.
Sauf que, parce qu'il faillait bien un 'Sauf que', exception (de taille, hélas !!!), les pages qui contiennent certains catégories de caractères Unicode (codés sur 3 ou 4 octets). Ceci est dû à une mauvaise gestion des données Unicode récupérées par PB. Un post a été créé dans la section 'Bugs' du forum US.
Je travaille néanmoins, grâce à STARGATE et Demivec, à trouver une solution pour palier à cet 'inconvénient'. Je la posterai dès que possible.
Source : Indentation d'un fichier HTML5
Code : Tout sélectionner
EnableExplicit
#IHTML_FICHIERHTML=0
#REGEX_HTMLBAL=0
#IHTML_REGEXHTMLBAL="</?\w+:?\w*((\s+(\w+-?+)+:?\w?+(\s*=\s*(?:"+#DQUOTE$+".*?"+#DQUOTE$+"|'.*?'|[^'"+#DQUOTE$+">\s]+))?)+\s*|\s*)/?>"
#IHTML_NBESPACES=2
#IHTML_FINDELIGNE=#LF$
Procedure Pc_Indentation_ChaineHTML(ArgChaineHTML.s)
Protected.i AncPosition=1 ; Position précédente dans la variable TexteFichier
Protected.i NouvPosition ; Position actuelle dans la variable TexteFichier après appel RegEx
Protected.i NouvLongChaine ; Longueur de la chaine textuelle entre deux balises après traitemeent Unicode
Protected.i LongChaine ; Longueur de la chaine textuelle entre deux balises
Protected.i NiveauBalise ; Niveau d'indentation
Protected.a Commentaire ; Commentaire HTML en cours de traitement (Booléen)
Protected.s TexteHTML ; Contenu final indenté
Protected.s ChaineFichier ; Contenu balise HTML ou Contenu entre deux balises
Protected.s ChaineModifiee ; ChaineFichier expurgée des espaces
Protected.s Balise ; Nom de la balise en cours
Protected.s ChaineCommentaire ; Commentaire HTML
; Suppression des LF, CR & TAB
ArgChaineHTML=ReplaceString(ReplaceString(ReplaceString(ArgChaineHTML,Chr(10),""),Chr(13),""),Chr(9),"")
ArgChaineHTML=Trim(ArgChaineHTML)
; Test entête fichier HTML
If UCase(Left(ArgChaineHTML,14))<>"<!DOCTYPE HTML"
MessageRequester("Analyse Balises et attributs HTML","Le fichier ne semble pas être un fichier HTML",#PB_MessageRequester_Error)
ProcedureReturn
EndIf
; Boucle lecture des balises
If CreateRegularExpression(#REGEX_HTMLBAL,#IHTML_REGEXHTMLBAL)
If ExamineRegularExpression(#REGEX_HTMLBAL,ArgChaineHTML)
While NextRegularExpressionMatch(#REGEX_HTMLBAL)
NouvPosition=RegularExpressionMatchPosition(#REGEX_HTMLBAL)
; Analyse du contenu entre deux balises ou commentaires HTML "<!-- blabla -->"
If AncPosition<>NouvPosition ; Texte ou commentaire
LongChaine=NouvPosition-AncPosition
ChaineFichier=Mid(ArgChaineHTML,AncPosition,LongChaine)
If ChaineFichier<>Space(LongChaine)
If Left(LTrim(ChaineFichier),4)="<!--" ; Balise début commentaire
If Right(RTrim(ChaineFichier),3)<>"-->" ; Commentaire encadrant:"<!-- blabla > <blabla> blabla <!-->"
Commentaire=#True
ChaineCommentaire=LTrim(ChaineFichier)
Else ; Commentaire non encadrant:<!--blabla-->
TexteHTML+Space(NiveauBalise*#IHTML_NBESPACES)+Trim(ChaineFichier)+#IHTML_FINDELIGNE
EndIf
ElseIf Right(RTrim(ChaineFichier),3)="-->" ; Balise fin commentaire encadrant
TexteHTML+Space(NiveauBalise*#IHTML_NBESPACES)+ChaineCommentaire+RTrim(ChaineFichier)+#IHTML_FINDELIGNE
Commentaire=#False
ChaineCommentaire=""
Else ; Texte entre deux balises
While FindString(ChaineFichier,Space(2))
ChaineFichier=ReplaceString(ChaineFichier,Space(2)," ")
Wend
If Right(TexteHTML,Len(#IHTML_FINDELIGNE)+1)=">"+#IHTML_FINDELIGNE
ChaineFichier=LTrim(ChaineFichier)
EndIf
TexteHTML+Space(NiveauBalise*#IHTML_NBESPACES)+ChaineFichier+#IHTML_FINDELIGNE
EndIf
EndIf
EndIf
; Analyse balise HTML
LongChaine=RegularExpressionMatchLength(#REGEX_HTMLBAL)
ChaineFichier=RegularExpressionMatchString(#REGEX_HTMLBAL)
ChaineModifiee=ReplaceString(ChaineFichier," ","")
If Commentaire ; Balise contenue dans un commentaire encadrant
ChaineCommentaire+ChaineFichier
ElseIf Left(ChaineModifiee,3)="<br" Or ; Balise ouvrante avec balise fermante non obligatoire (Possibilité d'en ajouter pour les cas non prévus et il y en a surement!)
Left(ChaineModifiee,3)="<hr" Or
(Left(ChaineModifiee,4)="<col" And Left(ChaineModifiee,9)<>"<colgroup") Or
Left(ChaineModifiee,4)="<img" Or
Left(ChaineModifiee,5)="<base" Or
Left(ChaineModifiee,5)="<area" Or
Left(ChaineModifiee,5)="<link" Or
Left(ChaineModifiee,5)="<meta" Or
Left(ChaineModifiee,6)="<frame" Or
Left(ChaineModifiee,6)="<input" Or
Left(ChaineModifiee,6)="<param" Or
Left(ChaineModifiee,6)="<track" Or
Left(ChaineModifiee,7)="<keygen" Or
Left(ChaineModifiee,7)="<source" Or
Left(ChaineModifiee,8)="<bgsound" Or
(Left(ChaineModifiee,2)<>"</" And Right(ChaineModifiee,2)="/>") ; Balise non encdrante (Par ex.:"<br/>","<a blabla />")
If Left(ChaineModifiee,3)="<br" And Right(TexteHTML,Len(#IHTML_FINDELIGNE)+1)<>">"+#IHTML_FINDELIGNE
TexteHTML=Left(TexteHTML,Len(TexteHTML)-Len(#IHTML_FINDELIGNE))
Else
TexteHTML+Space(NiveauBalise*#IHTML_NBESPACES)
EndIf
TexteHTML+ChaineFichier+#IHTML_FINDELIGNE
Else ; Balise encadrante
If Mid(Left(ChaineModifiee,2),2)<>"/" ; Balise encadrante ouvrante
;Obtenir le nom de la balise ouvrante
;Balise=Trim(Mid(ChaineFichier,2)) ; Important : Ne pas modifier l'ordre des 3 lignes suivantes ni les "factoriser"
;Balise=Trim(Left(Balise,Len(Balise)-1))
;Balise=StringField(Balise,1," ")
TexteHTML+Space(NiveauBalise*#IHTML_NBESPACES)+ChaineFichier+#IHTML_FINDELIGNE
NiveauBalise+1
ElseIf Mid(Left(ChaineModifiee,2),2)="/" ; Balise encadrante fermante
;Obtenir le nom de la balise fermante
;Balise=Trim(Mid(ChaineFichier,2)) ; Important : Ne pas modifier l'ordre des 4 lignes suivantes ni les "factoriser"
;Balise=Trim(Mid(Balise,2))
;Balise=Trim(Left(Balise,Len(Balise)-1))
;Balise=StringField(Balise,1," ")
NiveauBalise-Bool(NiveauBalise>0) ; Usage de Bool():On évite une erreur en cas de code HTML mal construit
TexteHTML+Space(NiveauBalise*#IHTML_NBESPACES)+ChaineFichier+#IHTML_FINDELIGNE
EndIf
EndIf
AncPosition=NouvPosition+LongChaine
Wend
If TexteHTML
Debug TexteHTML
EndIf
EndIf
EndIf
EndProcedure
Procedure Pc_Indentation_FichierHTML(ArgFichierHTML.s)
Protected.s TexteFichier ; Contenu du fichier HTML lu
If Trim(ArgFichierHTML)=""
MessageRequester("Analyse Balises et attributs HTML","Argument ArgFichierHTML invalide",#PB_MessageRequester_Error)
ProcedureReturn
EndIf
; Ouverture du fichier
If ReadFile(#IHTML_FICHIERHTML,ArgFichierHTML,#PB_UTF8)
TexteFichier=ReadString(#IHTML_FICHIERHTML,#PB_File_IgnoreEOL)
CloseFile(#IHTML_FICHIERHTML)
Pc_Indentation_ChaineHTML(TexteFichier)
Else
MessageRequester("Analyse Balises et attributs HTML","Erreur lors de l'accès au fichier",#PB_MessageRequester_Error)
EndIf
EndProcedure
Define.s FichierHTML
FichierHTML=OpenFileRequester("Sélectionner un fichier HTML","C:\","Fichiers HTML (*.htm*)|*.htm*",0)
If FichierHTML
Pc_Indentation_FichierHTML(FichierHTML)
EndIf
De même, j'ai élaboré un RegEx permettant de récupérer les attributs des balises HTML :
Ajout 1 : Analyse des attributs des balises d'un fichier HTML
Code : Tout sélectionner
EnableExplicit
Enumeration RegEX
#REGEX_HTMLBAL
#REGEX_HTMLATT
EndEnumeration
#IHTML_FICHIERHTML=0
#IHTML_REGEXHTMLBAL="</?\w+:?\w*((\s+(\w+-?+)+:?\w?+(\s*=\s*(?:"+#DQUOTE$+".*?"+#DQUOTE$+"|'.*?'|[^'"+#DQUOTE$+">\s]+))?)+\s*|\s*)/?>"
#IHTML_REGEXHTMLATT="(\S+)=["+#DQUOTE$+"']?((?:.(?!["+#DQUOTE$+"']?\s+(?:\S+)=|[>"+#DQUOTE$+"']))+.)["+#DQUOTE$+"']?"
Procedure Pc_Analyse_BalisesEtAttributesHTML(ArgFichierHTML.s)
Protected.i AncPosition=1 ; Position précédente dans la variable TexteFichier
Protected.i NouvPosition ; Position actuelle dans la variable TexteFichier après appel RegEx
Protected.i LongChaine ; Longueur de la chaine textuelle entre deux balises
Protected.i NbAttributs ; Nombre d'attributs d'une balise HTML
Protected.i Compteur ; Variable boucle For/Next
Protected.a Commentaire ; Commentaire HTML en cours de traitement (Booléen)
Protected.s TexteFichier ; Contenu du fichier HTML lu
Protected.s ChaineFichier ; Contenu balise HTML ou Contenu entre deux balises
Protected.s NomAttribut ; Nom de l'attribut HTML
Protected.s ValeurAttribut ; Valeur de l'attribut HTML
Dim Attributs.s(0)
If Trim(ArgFichierHTML)=""
MessageRequester("Analyse Balises et attributs HTML","Argument ArgFichierHTML invalide",#PB_MessageRequester_Error)
ProcedureReturn
EndIf
; Ouverture du fichier
If ReadFile(#IHTML_FICHIERHTML,ArgFichierHTML,#PB_UTF8)
TexteFichier=ReadString(#IHTML_FICHIERHTML,#PB_File_IgnoreEOL)
CloseFile(#IHTML_FICHIERHTML)
; Suppression des LF, CR & TAB
;TexteFichier=ReplaceString(ReplaceString(ReplaceString(TexteFichier,Chr(10),""),Chr(13),""),Chr(9),"")
ReplaceString(TexteFichier,Chr(10)," ",#PB_String_InPlace)
ReplaceString(TexteFichier,Chr(13)," ",#PB_String_InPlace)
ReplaceString(TexteFichier,Chr(9)," ",#PB_String_InPlace)
TexteFichier=Trim(TexteFichier)
; Test entête fichier HTML
If UCase(Left(TexteFichier,14))<>"<!DOCTYPE HTML"
MessageRequester("Analyse Balises et attributs HTML","Le fichier ne semble pas être un fichier HTML",#PB_MessageRequester_Error)
ProcedureReturn
EndIf
; Boucle lecture des balises
If CreateRegularExpression(#REGEX_HTMLBAL,#IHTML_REGEXHTMLBAL) And CreateRegularExpression(#REGEX_HTMLATT,#IHTML_REGEXHTMLATT)
If ExamineRegularExpression(#REGEX_HTMLBAL,TexteFichier)
While NextRegularExpressionMatch(#REGEX_HTMLBAL)
NouvPosition=RegularExpressionMatchPosition(#REGEX_HTMLBAL)
; Analyse du contenu entre deux balises ou commentaires HTML "<!-- blabla -->"
If AncPosition<>NouvPosition ; Texte ou commentaire
LongChaine=NouvPosition-AncPosition
ChaineFichier=Mid(TexteFichier,AncPosition,LongChaine)
If ChaineFichier<>Space(LongChaine)
If Left(LTrim(ChaineFichier),4)="<!--" And Right(RTrim(ChaineFichier),3)<>"-->" ; Balise début commentaire encadrant:"<!-- blabla > <blabla> blabla <!-->"
Commentaire=#True
ElseIf Right(RTrim(ChaineFichier),3)="-->" ; Balise fin commentaire encadrant
Commentaire=#False
EndIf
EndIf
EndIf
; Analyse balise HTML
LongChaine=RegularExpressionMatchLength(#REGEX_HTMLBAL)
ChaineFichier=RegularExpressionMatchString(#REGEX_HTMLBAL)
If Not Commentaire ; Balise autre qu'un commentaire
If Left(Trim(LTrim(ChaineFichier,"<")),1)<>"/" ; On exclut les balises fermantes
Debug "Balise HTML : "+ChaineFichier
; Analyse attributs
NbAttributs=ExtractRegularExpression(#REGEX_HTMLATT,ChaineFichier,Attributs())
If NbAttributs
Debug " Nombre d'attributs : "+NbAttributs
Debug " Attributs : "
NbAttributs-1
ReDim Attributs(NbAttributs)
For Compteur=0 To NbAttributs
NomAttribut=StringField(Attributs(Compteur),1,"=")
ValeurAttribut=StringField(Attributs(Compteur),2,"=")
;ValeurAttribut=Trim(StringField(Attributs(Compteur),2,"="),Chr(34)) ; Valeur de l'attribut sans les guillements
Debug " • "+NomAttribut+" : "+ValeurAttribut
Next
Else
Debug " Aucun attribut"
EndIf
Debug ""
EndIf
EndIf
AncPosition=NouvPosition+LongChaine
Wend
EndIf
EndIf
Else
MessageRequester("Analyse Balises et attributs HTML","Erreur lors de l'accès au fichier",#PB_MessageRequester_Error)
EndIf
EndProcedure
Define.s FichierHTML
FichierHTML=OpenFileRequester("Sélectionner un fichier HTML","C:\","Fichiers HTML (*.htm*)|*.htm*",0)
If FichierHTML
Pc_Analyse_BalisesEtAttributesHTML(FichierHTML)
EndIf