[ASP] Alles binnen een type span verwijderen

Pagina: 1
Acties:
  • 172 views sinds 30-01-2008
  • Reageer

  • Priet
  • Registratie: Januari 2001
  • Laatst online: 07:50

Priet

To boldly do what no one has..

Topicstarter
Ik ben al twee dagen bezig met het bedenken van een manier waarop ik bepaalde span-tags in HTML kan veranderen. Ik kom er maar niet uit :(

Het gaat om het volgende: Op een gegeven moment heb ik een stuk HTML waarin speciale tags in staan die vervangen moeten worden:
HTML:
1
<span type="icstag" unit="1" unitid="2" templateid="3">content</span>

Moet worden:
HTML:
1
<insert_unit unit="1" unitid="2" templateid="3" />

In principe levert dit geen probleem op, ik gebruik er regular expressions onder ASP voor, en dat gaat prima :)

Maar het probleem is wanneer geneste span-tags gebruikt worden. Zoals:
HTML:
1
2
3
4
5
6
7
8
9
10
<span type="icstag" unit="1" unitid="2" templateid="3">
  content
  <span type="icstag" unit="4" unitid="5" templateid="6">
    nog meer content
  </span>
  blablabla
  <span>
    iets in de span
  </span>
</span>

Ik moet nu dit zo gaan 'parsen' dat alleen de buitenste "icstag"-span-tag blijft staan. Alles wat er binnen staat mag weg. Het resultaat van bovenstaande HTML zou dan moeten zijn:
HTML:
1
<insert_unit unit="4" unitid="5" templateid="6" />

Met de ASP code die ik al had gaat dit niet lukken, omdat die als afsluitende tag de eerst </span> kiest. Maar als er sprake is van geneste tags gaat het dus fout, omdat de buitenste </span> later in de HTML staat.

Ik loop m'n hoofd nu al twee dagen te breken over dit probleem. Het lijkt zo simpel, maar ik kom er maar niet uit :'( Moet ik gaan bijhouden hoeveel <span>-tags er zijn geopend ofzo?

Mijn probeersels staan op http://peter.icrew.nl/reg.asp en de code die daarvoor:
ASP.NET Visual Basic:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
sHTML = "Blablabla<br><span contenteditable=""false"" style=""BORDER: red 1px dashed; MARGIN: 2px;"" unitid=""79"" unit=""4"" type=""icstag"" templateid=""21"">
{CONTENT}
</span>
<p>blabla2</p>
<span>hoi</span>
hallo
<span contenteditable=""false"" style=""BORDER: red 1px dashed; MARGIN: 2px;"" unit=""1"" unitid=""2"" type=""icstag"" templateid=""3"">
<span contenteditable=""false"" style=""BORDER: red 1px dashed; MARGIN: 2px;"" unitid=""79"" unit=""4"" type=""icstag"" templateid=""21"">
hoi
</span>Mjah
</span>"
Response.Write("<b>HTML-string:</b> " & Server.HTMLEncode(sHTML) & "<br><br>")

Dim objRegExp
Set objRegExp = New RegExp
objRegExp.IgnoreCase = True 
objRegExp.Global = True

Dim Match, Matches, sSpan, blnIcsTag, blnContentEditable
Dim MatchesAttributes, MatchAttributes, blnValidIcsTag
Dim iUnit, iUnitID, iTemplateID

objRegExp.pattern = "(<span((.|\n)*?)>((.|\n)*?)</span>)"
Set Matches = objRegExp.Execute(sHTML) 
For Each Match in Matches
    blnValidIcsTag = false
    
    'De span-tag
    sSpan = Match.SubMatches(0)
    Response.Write("<b>Span-tag:</b> " & Server.HTMLEncode(sSpan) & "<br>")
    'Controleren of dit een insert_unit is
    
    objRegExp.pattern = "type=""icstag"""
    blnIcsTag = objRegExp.test(sSpan)
    objRegExp.pattern = "contenteditable=""false"""
    blnContentEditable = objRegExp.test(sSpan)
    
    if (blnIcsTag AND blnContentEditable) Then
        Response.Write("<em>Valid tag found, now extracting attributes:</em><br>")
        'Haal de attributen eruit
        objRegExp.pattern = "\sunit=""([0-9]+)"""
        Set MatchesAttributes = objRegExp.Execute(sSpan)
        if MatchesAttributes.count > 0 Then
            iUnit = MatchesAttributes(0).SubMatches(0)
            Response.Write("<b>Unit:</b> " & iUnit & "<br>")
            Response.Write("<em>Unit valid, moving on to next attribute</em><br>")
            
            'UnitID
            objRegExp.pattern = "\sunitid=""([0-9]+)"""
            Set MatchesAttributes = objRegExp.Execute(sSpan)
            if MatchesAttributes.count > 0 Then
                iUnitID = MatchesAttributes(0).SubMatches(0)
                Response.Write("<b>UnitID:</b> " & iUnitID & "<br>")
                Response.Write("<em>UnitID valid, moving on to next attribute</em><br>")
                
                'TemplateID
                objRegExp.pattern = "\stemplateid=""([0-9]+)"""
                Set MatchesAttributes = objRegExp.Execute(sSpan)
                if MatchesAttributes.count > 0 Then
                    iTemplateID = MatchesAttributes(0).SubMatches(0)
                    blnValidIcsTag = true
                    Response.Write("<b>TemplateID:</b> " & iTemplateID & "<br>")
                    Response.Write("<em>TemplateID valid, icstag is valid</em><br>")
                else
                    Response.Write("<em>Template invalid, procedure stopped</em><br>")
                end if
            else
                Response.Write("<em>UnitID invalid, procedure stopped</em><br>")
            end if
        else
            Response.Write("<em>Unit invalid, procedure stopped</em><br>")
        end if
    end if
        
    if blnValidIcsTag Then
        Response.Write("<em>Now rewriting span-tag to insert_unit-tag</em><br><br>")
        objRegExp.pattern = sSpan
        sHTML = objRegExp.Replace(sHTML, "<insert_unit unit=""" & iUnit & """ unitid=""" & iUnitID & """ templateid=""" & iTemplateID & """ />")
    else
        Response.Write("<em>No icstag, just moving on to the next match</em><br><br>")
    end if

Next
Response.write("<b>Output:</b> " & Server.HTMLEncode(sHTML))

Volgens mij zit er ook wat kromme code tussen, of kan dit gewoon niet anders? Pff ik zie het echt ff niet meer.

Iemand nog een goed idee om me verder op weg te helpen?

/Edit: waarom werkt die asp code parses niet :?

[ Voor 21% gewijzigd door Priet op 19-10-2004 11:15 ]

"If you see a light at the end of a wormhole, it's probably a photon torpedo!"


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 19-05 21:24

NMe

Quia Ego Sic Dico.

Volgens mijn kun je geneste dingen echt niet oplossen met regexps... Maar wat je nu doet is niet eens optimaal gebruik van regexps, je zit een beetje tussen regular expressions en tokenizen in. Deze laatste methode zal hier wat effectiever zijn; in de search en op Google is hier ook meer dan genoeg over te vinden. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Verwijderd

1) Match met reguliere expressies alle span's en /span's in een matchcollection.
2) Loop er met een for next-lusje door heen.
3) Stop alle open spans + content in een stack (bv een dictionary).
4) Bij een close-span, haal de laatste span van de stack en verwerk deze zoals je die wil verwerken.

Sorry geen voorbeeldcode, die is (c)-mijn werk :)

  • Priet
  • Registratie: Januari 2001
  • Laatst online: 07:50

Priet

To boldly do what no one has..

Topicstarter
Hmm... nummer 1 en 2 gaan wel lukken.
Maar met een stack of dictionary heb ik nog niet eerder gewerkt in ASP. Wat is het idee daarachter?
Ik zoek eerst alle geldige <span type="icstag"> op en daarna loop ik vanaf dat punt verder tot ik een </span> tegenkom? Maar als ik in de tussentijd weer een </span> ben tegengekomen, moet ik een </span> verder zijn, etc.

Bedoelde je zoiets of zit ik nu een andere oplossing te verzinnen? :p

"If you see a light at the end of a wormhole, it's probably a photon torpedo!"


Verwijderd

Je moet alle spans doorlopen, niet alleen die je wilt hebben. Een stack kun je eenvoudig programmeren door een arraytje of een collection waar je iedere keer die span aan toevoegt. Als je dan een /span tegenkomt dan weet je dat die bij het laatste element in je array of collection hoort, of in stack-termen diegene die het laatst gepushed is.
Bij het verwerken van de /span haal je dat laatste element uit je array of collection, of in stack-termen je popped dat ding van de stack. Zodat de 'vorige' span nu bovenaan ligt op de stack (je dat letterlijk zien als bijvoorbeeld een stapel boeken, waarvan je alleen bij de bovenste kunt).

Een hele simpele (maar niet flexibele stack) implementeer je zo
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
dim stack(1000)
dim sp 
sp = 0

sub push(byval item)
   stack(sp) = item
   sp = sp + 1
end sub

function pop()
   sp = sp - 1
   pop = stack(sp)
end function

(warning: code not tested)

Heel veel compilers en interpreters werken met stacks, zelfs je processor intern. Een stack in een zogeheten LIFO (Last In, First Out). Zo heb je ook queue's die zie FIFO (First In, First Out). Dit zijn vrij elementaire technieken die naar mijn mening iedere programmeur uit zijn mouw zou moeten kunnen schudden. Maar ook mijn collega's hebben er wel eens moeite mee :'(

  • Priet
  • Registratie: Januari 2001
  • Laatst online: 07:50

Priet

To boldly do what no one has..

Topicstarter
Ha, thanks :)

Een stack ken ik verder wel. Heb er ook geen problemen mee. Maar ik wist ff niet hoe ik een stack in dit verhaal zou kunnen gebruiken :)

"If you see a light at the end of a wormhole, it's probably a photon torpedo!"


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 16:02

crisp

Devver

Pixelated

Indien je input well-formed is zou je met een XML-parser door de structuur kunnen wandelen, dan heb je al een tree. XSLT transformatie behoort dan ook tot de mogelijkheden.

[ Voor 20% gewijzigd door crisp op 20-10-2004 21:34 ]

Intentionally left blank


  • Priet
  • Registratie: Januari 2001
  • Laatst online: 07:50

Priet

To boldly do what no one has..

Topicstarter
Sorry voor deze late reactie, ik kon even niet bij de code.

Ik heb het namelijk al gedeeltelijk met een XML-parser opgelost. Maar die gebruik ik nu alleen nog voor het doorlopen van alle tags. Het vervangen/verwijderen van de tags doe ik met regular expressions. Dat moet toch ook kunnen met die XML-parser? Die manier lijkt mij veel efficiënter, maar het is mij (ondanks veel zoeken en lezen) tot op heden nog niet gelukt :/

Dit is mijn code zoals ik het nu doe:
ASP.NET Visual Basic:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<%
PUBLIC FUNCTION removeRenderdInsertUnit(sInput)
    dim sOutput, sOutput2, xmlObj, myErr, transform, root, iSpan

    sOutput = sInput
    ' objXML maakt haalt alle spaties (bij />) eruit, waardoor de vergelijking tijdens de replace
    ' Niet meer werkt... daarom alle spaties er van tevoren uithalen...
    sOutput = replace(sOutput, " />", "/>")

    sOutput2 = replace(sOutput,"&","-=amp=-")
    sOutput2 ="<RootElement>" & sOutput & "</RootElement>"
    
    'omzetten van sOutput naar XML document
    set xmlObj = Server.CreateObject ("MSXML2.DOMDocument.4.0")
    xmlObj.async = false
    xmlObj.preserveWhiteSpace = False
    xmlObj.resolveExternals = False
    xmlObj.loadXML(sOutput2)
    if xmlObj.parseError.errorCode <> 0 then
        set myErr = xmlObj.parseError
        transform = transform &"<br/><br/>Error: "&myErr.errorCode&": "&myErr.reason&vbcrlf&": <I><BR/>"&myErr.srcText&"</I><br/><br/>"
        transform = transform & "<hr/>"&vbcrlf&vbcrlf&replace(replace(replace(xml, "<", "&lt;"), ">", "&gt;"), vbcrlf, "<br/>")&vbcrlf&vbcrlf&"<hr/>"
        Response.write transform
        sOutput = Null
    else        
        redim arrTags(2,0)
        Set root = xmlObj.documentElement
        outputNode root, 0, arrTags
    
        For iSpan = 0 to ubound(arrTags, 2) - 1
            sOutput = replace(sOutput, arrTags(0, iSpan), arrTags(1, iSpan))
        Next
    end if
    
    removeRenderdInsertUnit = sOutput
END FUNCTION 'removeRenderdInsertUnit
    
private sub outputNode(node, iNiveau, ByRef arrTags)
    dim blnIcsTag, sType, iUnit, iUnitID, iTemplateID, iAantalTags, child
    
    blnIcsTag = false
    if node.nodeType = 1 Then
        if node.attributes.length > 0 then
            sType = Null
            iUnit = Null
            iUnitID = Null
            iTemplateID = Null
            
            iAantalTags = Null
            sType = node.getAttribute("type")
            iUnit = node.getAttribute("unit")
            iUnitID = node.getAttribute("unitid")
            iTemplateID = node.getAttribute("templateid")
            if (len(sType) > 0) AND (len(iUnit) > 0) AND (len(iUnitID) > 0) AND (len(iTemplateID) > 0) Then
                blnIcsTag = true
                iAantalTags = ubound(arrTags, 2)
                redim preserve arrTags(2, iAantalTags + 1)
                arrTags(0, iAantalTags) = node.xml
                arrTags(1, iAantalTags) = "<insert_unit unit=""" & iUnit & """ unitid=""" & iUnitID & """ templateid=""" & iTemplateID & """ />"
            end if
        end if
    end if 

    if Not blnIcsTag AND node.hasChildNodes() Then
        For Each child In node.childNodes
            outputNode child, iNiveau + 1, arrTags
        Next
    End if
end sub
%>

Kan ik in deze opzetten direct de boom aanpassen zónder gebruik te moeten maken van de replace functie?

"If you see a light at the end of a wormhole, it's probably a photon torpedo!"

Pagina: 1