[英]How to merge sibling elements with same attributes?
考虑这样的XML输入:
<root>
<sub>
<p att1=0 att2=1><i>foo</i></p>
<p att1=1 att2=1><i>bar</i></p>
<p att1=0 att2=0><i>baz</i></p>
<p att1=0 att2=1><i>bazz</i></p>
</sub>
</root>
应将其转换为:
<root>
<sub>
<p att1=0 att2=1><i>foo</i><i>bazz</i></p>
<p att1=1 att2=1><i>bar</i></p>
<p att1=0 att2=0><i>baz</i></p>
</sub>
</root>
(因为<i>foo</i>
和<i>bazz</i>
p
父元素都是兄弟姐妹,并且具有相同的属性。)
如何使用HXT箭头进行这种转换?
好的,我可以尝试:该代码首先在同级的父级收集所有属性列表,然后对所有不同的属性列表进行合并:
{-# LANGUAGE Arrows #-}
module Main
where
import Data.List
import Text.XML.HXT.Core
example="\
\<root>\
\ <sub>\
\ <p att1=\"0\" att2=\"1\"><i>foo</i></p>\
\ <p att1=\"1\" att2=\"1\"><i>bar</i></p>\
\ <p att1=\"0\" att2=\"0\"><i>baz</i></p>\
\ <p att1=\"0\" att2=\"1\"><i>bazz</i></p>\
\ </sub>\
\</root>"
get_attrs name = getChildren >>> hasName name >>> proc x -> do
a <- listA (((
getAttrName
&&& (getChildren >>> getText)) ) <<< getAttrl ) -< x
returnA -< a
has_attrs atts = proc x -> do
a <- listA (((
getAttrName
&&& (getChildren >>> getText)) ) <<< getAttrl ) -< x
if (a == atts)
then returnA -< x
else none -<< ()
mk_attrs atts = map f atts
where
f (n, v) = sqattr n v
mergeSiblings_one inp name att = catA (map constA inp)
>>> mkelem name
(mk_attrs att)
[getChildren
>>> hasName name >>> has_attrs att >>> getChildren ]
mergeSiblings_core name = proc x -> do
a <- listA (get_attrs name >>. (sort.nub) ) -< x
b <- listA this -< x
c <- listA (getChildren >>> neg (hasName name)) -< x
catA ((map (mergeSiblings_one b name) a) ++ (map constA c) ) -<< ()
is_parent_of name = getChildren >>> hasName name
mergeSiblings name = processTopDownUntil (
is_parent_of name `guards` mergeSiblings_core name
)
stuff = mergeSiblings "p"
main :: IO ()
main
= do
x <- runX (
configSysVars [withTrace 1]
>>> readString [withValidate no
,withPreserveComment yes
,withRemoveWS yes
] example
>>> setTraceLevel 4
>>> stuff >>> traceTree >>> traceSource
)
return ()
<root>
<p att1="0" att2="0">
<i>baz</i>
</p>
<p att1="0" att2="1">
<i>foo</i>
<i>bazz</i>
</p>
<p att1="1" att2="1">
<i>bar</i>
</p>
</root>
上面的版本将合并的子级放在最前面,将不匹配的子级放在父节点的新子级列表中:一个不错的变化是:将每个合并的子级插入第一个旧兄弟节点的旧位置,并且不要更改非合并节点的顺序。 例如那个
<other>1</other><p><a/></p><other>2</other><p><b/></p>
转化为
<other>1</other><p><a/><b/></p><other>2</other>
而不是:
<p><a/><b/></p><other>1</other><other>2</other>
由于我是HXT和箭头的新手,如果有更多简洁/ HXT0惯用/优美的答案,我也不会感到惊讶。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.