从XML缓慢导入和自动生成代码

时间:2014-03-11 11:46:29

标签: haskell

我一直在玩Haskell并编写一些代码来解析DICOM医学图像。代码是here。我想创建一个将接收ByteString并返回名称的函数。因此,某个ByteString(实际上是从ByteString获取的两个Int64)将返回PatientName或StudyDate。有数千个这些,它们都包含在XML文件中。因此,为了创建函数,我解析XML文件并生成所需的函数并使用

输出到文件
writeTagNameFromElemGroup :: FilePath -> [(String,String,String,String)] -> IO()
writeTagNameFromElemGroup fp tups = init >> Prelude.appendFile fp ( Prelude.drop 0 tags )
    where init = Prelude.appendFile fp "\ntagNameFromElem :: Element -> Group -> String\ntagNameFromElem e g\n"
      tags = LS.concat $ Prelude.map (\tup -> "    | " ++ (writeTup tup) ++ "\n") filTups
      hexInt x = show . readHex $ x
      filTups = LS.filter (\(w,x,y,z) -> Prelude.length w == 4 && Prelude.length x ==4 ) tups

这将在Tags.hs中创建所需的功能

tagNameFromElem :: Int64 -> Int64 -> String
tagNameFromElem e g
    | e == 8 && g == 1 = "LengthToEnd"
    | e == 8 && g == 5 = "SpecificCharacterSet"
    | e == 8 && g == 6 = "LanguageCodeSequence"
    | e == 8 && g == 8 = "ImageType"
    | e == 8 && g == 16 = "RecognitionCode"
    | e == 8 && g == 18 = "InstanceCreationDate"
    | e == 8 && g == 19 = "InstanceCreationTime"
    | e == 8 && g == 20 = "InstanceCreatorUID"
    | e == 8 && g == 22 = "SOPClassUID"
    | e == 8 && g == 24 = "SOPInstanceUID"
    | e == 8 && g == 26 = "RelatedGeneralSOPClassUID"
    | e == 8 && g == 27 = "OriginalSpecializedSOPClassUID"
    ..... > 2000 more

每隔一段时间就有一个像

这样的特殊情况
    | e == 1000 && mod (g -5) 10 == 0 = "ShiftTableTriplet"

让我只使用地图。

现在这种方法有效但是需要很长时间才能加载(超过一分钟)整体,这让我觉得我没有这样做,应该怎么做。为了重现我建议克隆repo并加载Tags.hs.

SSCE

writeFunc :: (Num x, Show x) => FilePath -> [x] -> IO()
writeFunc fp xs  = init >> Prelude.appendFile fp ( maps ) >> Prelude.appendFile fp "|  otherwise = 0 "
    where init = Prelude.appendFile fp "mapVal :: Int -> Int \nmapVal x\n    "
          maps = concat $ Prelude.map (\x -> "| x == " ++ show x ++ " = " ++ show (x +1 ) ++ "\n    ") xs

使用长列表〜几千个值并尝试导入生成的文件

1 个答案:

答案 0 :(得分:2)

这个答案是基于bheklilr在问题的评论中提出的建议。代码生成取决于您。

我查看了您的代码,发现只有两个值ege == 28e == 1000施加了特殊条件。因此,处理不同功能的人会更好。请选择比以下更好的名字。

e28 :: Map Int64 String
e28 = fromList [ (0, "CodeLabel"), (2, "NumberOfTables"), ... ]

e1000 :: Map Int64 String
e1000 :: fromList [ (0, "EscapeTriplet"), (1, "RunLengthTriplet"), ... ]

以前地图的键取自您的特殊情况谓词:mod (g - key) 10 == 0

e == 1010也很特殊的情况,因为它不依赖g。它总是" ZonalMap",所以它稍后会被处理。

现在,只需使用g作为关键字创建其余地图。

e40 :: Map Int64 String
e40 = fromList [ (2, "SamplesPerPixel"), (3, "SamplesPerPixelUsed"), ... ]

e84 :: Map Int64 String
e84 = fromList [ ... ]

...

从常规e(即不是28,1000或1010)创建地图到相应的地图:

regularE :: Map Int64 (Map Int64 String)
regularE e = fromList [ (40, e40), (84, e84), ... ]

总结一下:

import Control.Monad

tagNameFromElem :: Int64 -> Int64 -> Maybe String
tagNameFromElem   28 g = lookup e28 (mod g 10)
tagNameFromElem 1000 g = lookup e1000 (mod g 10)
tagNameFromElem 1010 _ = Just "ZonalMap"
tagNameFromElem    e g = lookup regularE e >>= (`lookup` g)

lookup函数来自Data.Map,以防需要资格认证。使用Maybe处理eg未映射到有效标记名称的情况,而不是硬编码的"未找到"字符串。

请注意,我还没有测试过此代码;我现在不在家。

如果需要,请尝试使用IntMap代替Map。在这种情况下,您需要使用常规Int,但这对此项目可能有用。