2009-03-20 15 views
0

Je reçois des données html du serveur distant et avant de les afficher dans l'interface utilisateur, j'ai besoin de faire quelques modifications, par exemple supprimer des compteurs, remplacer des liens, etc. Changement de lien spécifique n'est pas un gros problème, mais quand il s'agit d'un traitement avancé, j'ai quelques problèmes.Il est nécessaire de remplacer (supprimer) quelques attributs tag html (pas un tag lui-même - il y a beaucoup d'exemples sur internet ce). Par exemple: supprimez tous les gestionnaires onmouseover des boutons. Je sais que XPath serait un ajustement parfait pour un tel problème, mais je ne le connais pas du tout et bien que mon information soit XHTML-plainte, il est stocké dans une variable de chaîne et non interrogeable :(. Donc j'essaie d'utiliser les expressions régulières pour résoudre ce problème, sans succès pour l'instant. Je suppose que c'est une erreur dans le modèle ...C# - Traitement des attributs de balises html

public string Processing (string Source, string Tag, string Attribute) 
{  
return System.Text.RegularExpressions.Regex.Replace(Source, string.Format(@"<{0}(\s+({1}=""([^""]*)""|\w+=(""[^""]*""|\S+)))+>", Tag, Attribute), string.Empty); 
} 

... 

string before = @"<input type=""text"" name=""Input"" id=""Input"" onMouseOver=""some js to be eliminated"">"; 
string after = Processing(before,"input","onMouseOver"); 
// expected : <input type="text" name="Input" id="Input">" 

Répondre

1

C'est une approche intéressante, mais comme l'a dit Bobince, vous ne pouvez traiter qu'un attribut par match. Cette expression rationnelle correspond à tout à l'attribut que vous êtes intéressé par:

@"(<{0}\b[^>]*?\b){1}=""(?:[^""]*)""" 

Ensuite, vous utilisez « $ 1 » comme chaîne de remplacement pour rebranchant tout sauf l'attribut. Cette approche nécessite que vous fassiez un passage séparé sur la chaîne pour chacune de vos paires cible/attribut, et au début de chaque passe, vous devez créer et compiler la regex. Pas très efficace, mais si la corde n'est pas trop grande ça devrait aller. Un problème beaucoup plus important est qu'il n'attrapera pas les attributs en double; S'il y a deux attributs "onmouseover" sur un bouton, vous n'attraperez que le premier. Si je faisais cela en C#, j'utiliserais probablement la regex pour correspondre à la cible, puis j'utiliserais un MatchEvaluator pour supprimer tous les attributs cibles en même temps. Mais sérieusement, si la chaîne est vraiment bien formée en XML, il n'y a pas d'excuse pour ne pas utiliser d'outils spécifiques au XML pour le traiter - c'est ce que XML a été inventé pour.

+0

Il semble que la parenthèse de fermeture du groupe soit manquante (regex ne compile pas). Expression fixe: @ "(<{0}\b[^>] *? \ B) ({1} =" "(?: [^" "] *)" ")" – Jaded

+0

Et, bien sûr, merci beaucoup, votre indice est en fait ce que J'ai eu besoin. – Jaded

+0

Oups. En fait, le support rond d'ouverture juste avant le {1} ne devrait pas être là. Il est inutile de capturer l'attribut, puisque tout ce que vous faites est de le supprimer. –

1

Je sais que cela est une question au sujet (fixation) RegEx, mais une autre approche consiste à charger votre xHtml dans un XmlDocument (il accepte une chaîne) ou XDocument et utilise XPath ou Linq

+0

Eh bien, j'apprécié un exemple simple XPath;) – Jaded

0

Je pense que votre approche est trop simpliste.Analyse d'un HTML en utilisant des expressions régulières pourrait être beaucoup plus difficile que vous ne le pensez. vous de prendre une look at this question.

+0

en utilisant un certain cadre tiers pour tel. une tâche serait "beaucoup plus" aussi, je sais que HTML Agility Pack est assez puissant, b Je vais essayer de l'utiliser au cas où c'est vraiment nécessaire. – Jaded

0

Je sais que XPath serait un ajustement parfait pour ce problème

Tout à fait. Ou toute autre technique basée sur un analyseur XML, telle que les méthodes DOM.

Il est vraiment pas une chose difficile à apprendre: farcir votre chaîne dans la méthode XmlDocument.LoadXml() puis appelez selectNodes() sur elle avec quelque chose comme « // tagname [@attrname] » pour obtenir une liste des éléments avec l'attribut indésirable. Peasy.

je suis en train d'utiliser des expressions régulières pour résoudre ce problème, sans succès

Qu'est-ce avec regexes? Les gens continuent à les utiliser même quand ils savent que c'est la mauvaise chose, même s'ils sont souvent illisibles et difficiles à corriger (comme le montre l'interminable "pourquoi mon regex ne fonctionne-t-il pas?").

Alors qu'est-ce qui est si attirant avec ces choses damnées? Il y a plusieurs questions sur SO chaque jour à propos de l'analyse [X] [HT] ML avec regex, tous ont répondu "n'utilisez pas regex, regex n'est pas assez puissant pour analyser HTML". Mais d'une manière ou d'une autre, ça ne passe jamais.

Je suppose que c'est une erreur dans le modèle ...

Eh bien, le modèle semble essayer de faire correspondre des balises entières pour le remplacer par une chaîne vide, ce qui est pas ce que vous voulez. Au lieu de cela, vous voudriez cibler uniquement l'attribut, puis pour vous assurer que seuls les attributs d'une balise "< ..." "comptent, vous devez utiliser une assertion lookbehind négative -" (?! < tag) ". Mais vous ne pouvez généralement pas avoir une assertion lookbehind de longueur variable, dont vous auriez besoin pour autoriser d'autres attributs entre le nom du tag et l'attribut ciblé.

De plus, votre clause '\ S +' a le potentiel d'engloutir de grandes quantités de contenu indésirable. Comme vous avez du XHTML bien formé, les attributs correctement cités vous sont garantis, donc vous n'en avez pas besoin de toute façon.

Mais l'erreur n'est pas le modèle. C'est regex.

+0

Bien sûr. Regex sont utiles pour de nombreux problèmes. Mais si les questions sur SO sont quelque chose à faire - et à en juger par la quantité d'horreur de codage réel que j'ai vu, ils le sont probablement - une majorité d'utilisation de regex est totalement inappropriée. – bobince

+0

Eh bien ... Je pensais que les expressions régulières sont mieux que quelque chose comme suit: Source.Substring (Source.IndexOf (Attribute), Attribute.Length + ParameterLength) ou quelque chose ... Plus un document que je travaille avec semble ne pas être complètement plainte XHTML. Il a l'espace de noms xml inclus, mais échoue la validation. – Jaded

+0

"Validation" n'est pas important pour le traitement en XML, il doit seulement être "bien formé". Sinon, il existe des parseurs HTML tels que le Pack d'agilité qui sont encore beaucoup plus faciles à utiliser que de tenter de pirater une regex. – bobince

0

Ainsi, le code est réécrite:

public static string Process(string Source, string Tag, string Attribute) 
{ 
     return Regex.Replace(Source, string.Format(@"(<{0}\b[^>]*?\b)({1}=""(?:[^""]*)"")", Tag, Attribute), "$1");     
} 

Je l'ai testé et il fonctionne très bien.

string before = @"<input type=""text"" name=""Input"" id=""Input"" onMouseOver=""some js to be eliminated1""/>" 
     + "\r\n" + @"<input type=""text"" name=""Input2"" id=""Input2"" onMouseOver=""some js to be eliminated2"">" 
     + "\r\n" + @"<input type=""text"" name=""Input3"" id=""Input3"" onMouseOver=""some js to be eliminated3"">";    
string after = Process(before, "input", "onMouseOver"); 
//<input type="text" name="Input" id="Input" /> 
//<input type="text" name="Input2" id="Input2" > 
//<input type="text" name="Input3" id="Input3" > 

Pour l'instant le problème est résolu. J'essaierais d'utiliser une solution de contournement liée à xml, mais il semblerait que, avant de créer XmlDocument, je doive retravailler l'entrée html, car d'après le validateur w3c, il contient des erreurs. Il commence comme suit

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
    <HTML xmlns="http://www.w3.org/1999/xhtml"> 
    <HEAD> 
    <TITLE>page title</TITLE> 

Sur LoadXml je reçois « System.Xml.XmlException de Marqueur « > » est pas acceptable - ligne 1 poste 63. Ajout de la définition du type de document fait la même exception, mais cette fois sur « - .? 'marqueur incorrect, '>' attendu

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
     "http://www.w3.org/TR/html4/strict.dtd"> 

Toutes les idées ou le laisser aller)

+0

S'il est dit en majuscule, ce n'est pas XHTML - probablement le legs original - le doctype HTML est plus approprié et le 'xmlns' n'est que mensonges. – bobince

+0

(Et nous ne pouvons pas le voir à partir de l'entrée publiée, mais l'erreur sur '-' est généralement le signe d'un commentaire brisé comme "" , qui est invalide à la fois en HTML et XHTML, mais sera géré correctement par les navigateurs et le Pack Agility. – bobince

Questions connexes