2014-07-17 10 views
5

Próbuję parsować niektóre skrobanie HTML do prawidłowego xml, przy użyciu this function.Dlaczego nie mogę przetworzyć skradzionego kodu HTML na XML?

Mój kod testowy (z funkcją htmlParse skopiować z bloga Ben Nadel'S):

<cfscript> 
    // I take an HTML string and parse it into an XML(XHTML) 
    // document. This is returned as a standard ColdFusion XML 
    // document. 
    function htmlParse(htmlContent, disableNamespaces = true){ 

     // Create an instance of the Xalan SAX2DOM class as the 
     // recipient of the TagSoup SAX (Simple API for XML) compliant 
     // events. TagSoup will parse the HTML and announce events as 
     // it encounters various HTML nodes. The SAX2DOM instance will 
     // listen for such events and construct a DOM tree in response. 
     var saxDomBuilder = createObject("java", "com.sun.org.apache.xalan.internal.xsltc.trax.SAX2DOM").init(); 

     // Create our TagSoup parser. 
     var tagSoupParser = createObject("java", "org.ccil.cowan.tagsoup.Parser").init(); 

     // Check to see if namespaces are going to be disabled in the 
     // parser. If so, then they will not be added to elements. 
     if (disableNamespaces){ 

     // Turn off namespaces - they are lame an nobody likes 
     // to perform xmlSearch() methods with them in place. 
     tagSoupParser.setFeature(
     tagSoupParser.namespacesFeature, 
     javaCast("boolean", false) 
     ); 

     } 

     // Set our DOM builder to be the listener for SAX-based 
     // parsing events on our HTML. 
     tagSoupParser.setContentHandler(saxDomBuilder); 

     // Create our content input. The InputSource encapsulates the 
     // means by which the content is read. 
     var inputSource = createObject("java", "org.xml.sax.InputSource").init(
     createObject("java", "java.io.StringReader").init(htmlContent) 
     ); 

     // Parse the HTML. This will trigger events which the SAX2DOM 
     // builder will translate into a DOM tree. 
     tagSoupParser.parse(inputSource); 

     // Now that the HTML has been parsed, we have to get a 
     // representation that is similar to the XML document that 
     // ColdFusion users are used to having. Let's search for the 
     // ROOT document and return is. 
     return(
     xmlSearch(saxDomBuilder.getDom(), "/node()")[ 1 ] 
     ); 

    } 
</cfscript> 
<cfset html='<tr > <td align="center"> <span id="id1" >Compliance Review</span> </td><td class="center"> <span id="id2" >395.8(i)</span> </td><td align="left"> <span id="id3" >Failing to submit a record of duty status within 13 days </span> </td><td class="center" > <span id="id4">4/17/2014</span> </td> </tr>' /> 
<cfset parsedData = htmlParse(html) /> 

(HTML jest odbierany w tym formacie z innej funkcji, ale starałem hardcoding ciąg do teraz prześledzić problem)

pojawia się następujący błąd:.

NOT_FOUND_ERR: An attempt is made to reference a node in a context where it does not exist. 
The error occurred in myfilePath/myfileName.cfm: line 42 

40 :  // Parse the HTML. This will trigger events which the SAX2DOM 
41 :  // builder will translate into a DOM tree. 
42 :  tagSoupParser.parse(inputSource); 

Co jest nie tak? Jak mogę to poprawić?

+0

Gdy używasz ColdFusion do wywołania metody, jesteś za pomocą prostej Java tutaj. Wydaje mi się, że dane wejściowe nie są dobrze sformatowane lub występuje błąd w analizatorze składni. –

+0

@ J.T. - czy nie chodzi o to, że powinien działać także dla "brudnego" html, a dane wejściowe nie muszą być dobrze sformatowane? – froadie

+1

@froadie Nie jesteś pewien problemów Tagoup, ale użyłem Jsoup i działa dobrze. Te dwa linki mogą być przydatne. http://www.raymondcamden.com/2012/4/6/jsoup-adds-jQuerylike-parsing-in-Java i http://www.bennadel.com/blog/2358-parsing-traversing-and-mutating- html-with-coldfusion-and-jsoup.htm –

Odpowiedz

2

Nie używałem TagSoup, ale od lat używam jTidy z doskonałymi wynikami, aby pobrać HTML dostarczony przez użytkownika z różnych źródeł (w tym MS Word) i oczyścić go tak, aby zwracał XHTML.

Możesz spróbować jTidy na tym samym dokumencie, upuszczając jar jTidy na ścieżkę klasy lub używając JavaLoader, aby go załadować. Ponieważ jesteś na CF10, możesz użyć this method to include the JAR.

Następnie, oto jak zadzwonić jTidy w CFScript:

jTidy = createObject("java", "org.w3c.tidy.Tidy"); 

jTidy.setQuiet(false); 
jTidy.setIndentContent(true); 
jTidy.setSmartIndent(true); 
jTidy.setIndentAttributes(true); 
jTidy.setWraplen(1024); 
jTidy.setXHTML(true); 
jTidy.setNumEntities(true); 
jTidy.setConvertWindowsChars(true);    
jTidy.setFixBackslash(true);  // changes \ in urls to/
jTidy.setLogicalEmphasis(true);  // uses strong/em instead of b/i 
jTidy.setDropEmptyParas(true); 

// create the in and out streams for jTidy 
readBuffer = CreateObject("java","java.lang.String").init(parseData).getBytes(); 
inP = createobject("java","java.io.ByteArrayInputStream").init(readBuffer); 
outx = createObject("java", "java.io.ByteArrayOutputStream").init(); 

// do the parsing 
jTidy.parse(inP,outx); 
outstr = outx.toString(); 

ten powróci poprawny XHTML, który można kwerendy przeciwko z XPath. I owinięty powyższe pod funkcję makeValid(), a następnie prowadził ją przed swoim HTML:

<cfset html='<tr > <td align="center"> <span id="id1" >Compliance Review</span> </td><td class="center"> <span id="id2" >395.8(i)</span> </td><td align="left"> <span id="id3" >Failing to submit a record of duty status within 13 days </span> </td><td class="center" > <span id="id4">4/17/2014</span> </td> </tr>' /> 
<cfset out = makeValid(html) /> 
<cfdump var="#xmlParse(out)#" /> 

I tutaj było wyjście:

Picture of the cfdump output from xmlParse()

+0

Tak naprawdę skończyłem używając Jsoupa zgodnie z komentarzem @ GauravS ... Ale dziękuję ci za to, a link o tym, jak dołączyć słoiki, również był przydatny. – froadie

Powiązane problemy