Skip to main content

Importing malformed XML: Import[... "XMLObject"] vs ImportString[..., "XML"]


It appears that Import[ url , "XMLObject" ] is more forgiving of improperly formatted XML than ImportString[ string, "XML"]. For example, Mathematica is happy to do this


popNamesXML = 
Import["http://uscode.house.gov/popularnames/popularnames.htm",
"XMLObject"];

but complains about this


popNames = 

URLFetch["http://uscode.house.gov/popularnames/popularnames.htm"];
xml = ImportString[popNames, "XML"];

enter image description here


and barks about utf8 encoding for this


ImportString[popNames, {"HTML", "XMLObject"}]

In the Trace of the first snippet it appears these options are being passed to XMLGetString:


{"NormalizeWhitespace"->True,"IncludeNamespaces"->Automatic,
"ValidateAgainstDTD"->Automatic,"IncludeEmbeddedObjects"->None,

"AllowRemoteDTDAccess"->True,"ReadDTD"->True,"IncludeDefaultedAttributes"->False,
"AllowUnrecognizedEntities"->Auomatic,"PreserveCDATASections"->False}

But passing these to ImportString or directly to XMLGetString still results in the same errors.


This answer may be of interest but does not seem to be the problem, though I could be wrong. I tinkered with the suggestion there without luck. Does anyone know if/how I can make ImportString behave nicely here?



Answer



I am using Mathematica 8.0.4 and have no URLFetch command, so I have used Wget to download this 5915505 bytes file:


wget http://uscode.house.gov/popularnames/popularnames.htm

After downloading I evaluated



popNamesXML = Import["popularnames.htm", "XMLObject"]

And got the XMLObject without any errors. Then I Imported this file as "Text" and tried to get the XMLObject using ImportString:


popNames = Import["popularnames.htm", "Text"];
ImportString[popNames, {"HTML", "XMLObject"}]

I got a couple if the $CharacterEncoding::utf8 errors on the last step, instead of the XMLObject I got the plaintext version of the page.


So it is clear at least that the problem is not in URLFetch but in ImportString itself. I think it is worth to report it to Wolfram Support.


One workaround is to Export the popNames into a file with extension .htm, then Import it:


Export["popNames.htm", popNames, "Text"]

popNamesXML = Import["popNames.htm", "XMLObject"]

It poduces the desired XMLObject.


Another workaround is to use CharacterEncoding -> "WindowsANSI" option:


popNamesXML2 = ImportString[popNames, {"XHTML", "XMLObject"}, CharacterEncoding -> "WindowsANSI"]

It produces identical XMLObject without errors:


popNamesXML2 === popNamesXML



True

So the problem is that ImportString by default incorrectly chooses the "UTF8" encoding instead of "WindowsANSI". It looks like a bug since it is not related to global $CharacterEncoding variable: setting


$CharacterEncoding = "WindowsANSI"

does not change anything.


On the Documentation page for the "HTML" format we read:



If the character encoding of the file is not specified in the HTML file, Import uses the encoding specified by CharacterEncoding. A complete list of possible encodings is given by $CharacterEncodings.




This statement seems to be misleading for two reasons:


1) The default value for CharacterEncoding is Automatic and it is not clear how ImportString should behave in the case when character encoding is not specified in the HTML file.


2) In our case the character encoding IS specified in the HTML file on the first and fourth lines AND IS ignored when we provide explicit value for the CharacterEncoding option:





Manually deleting the "encoding='UTF-8'" and "charset=UTF-8" from the file in a plain text editor does fix incorrect behavior: now we get identical XMLObject without errors:


popNamesXML === ImportString[Import["popularnames_fixed.htm", "Text"], {"XHTML", "XMLObject"}]



True

I have also checked the server response (which should also contain the encoding information) using the -S switch of Wget:


wget -S http://uscode.house.gov/popularnames/popularnames.htm

and got



Content-Type: text/html;charset=UTF-8



It means Import gets no correct information about encoding from the server but is able to determine the correct encoding in this case.



So the final diagnosis is similar to what mfvonh suggested: Import can automatically handle the cases when incorrect encoding is specified in an HTML file while ImportString in such cases needs the correct encoding specified through the CharacterEncoding option.


Comments

Popular posts from this blog

mathematical optimization - Minimizing using indices, error: Part::pkspec1: The expression cannot be used as a part specification

I want to use Minimize where the variables to minimize are indices pointing into an array. Here a MWE that hopefully shows what my problem is. vars = u@# & /@ Range[3]; cons = Flatten@ { Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; Minimize[{Total@((vec1[[#]] - vec2[[u[#]]])^2 & /@ Range[1, 3]), cons}, vars, Integers] The error I get: Part::pkspec1: The expression u[1] cannot be used as a part specification. >> Answer Ok, it seems that one can get around Mathematica trying to evaluate vec2[[u[1]]] too early by using the function Indexed[vec2,u[1]] . The working MWE would then look like the following: vars = u@# & /@ Range[3]; cons = Flatten@{ Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; NMinimize[ {Total@((vec1[[#]] - Indexed[vec2, u[#]])^2 & /@ R...

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

What is and isn't a valid variable specification for Manipulate?

I have an expression whose terms have arguments (representing subscripts), like this: myExpr = A[0] + V[1,T] I would like to put it inside a Manipulate to see its value as I move around the parameters. (The goal is eventually to plot it wrt one of the variables inside.) However, Mathematica complains when I set V[1,T] as a manipulated variable: Manipulate[Evaluate[myExpr], {A[0], 0, 1}, {V[1, T], 0, 1}] (*Manipulate::vsform: Manipulate argument {V[1,T],0,1} does not have the correct form for a variable specification. >> *) As a workaround, if I get rid of the symbol T inside the argument, it works fine: Manipulate[ Evaluate[myExpr /. T -> 15], {A[0], 0, 1}, {V[1, 15], 0, 1}] Why this behavior? Can anyone point me to the documentation that says what counts as a valid variable? And is there a way to get Manpiulate to accept an expression with a symbolic argument as a variable? Investigations I've done so far: I tried using variableQ from this answer , but it says V[1...