1

次のような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>

(との両方のp親要素は兄弟で<i>foo</i>あり<i>bazz</i>、同じ属性を持っているためです。)

HXT矢印を使用してこのような変換を行う方法は?

4

1 に答える 1

1

OK、私の試みがあります:コードは最初に兄弟の親ですべての属性リストを収集し、次に異なるすべての属性リストに対してマージを実行します:

{-# 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と矢印に慣れていないので、もっと簡潔/HXT0idiomatic/エレガントな答えがあったとしても驚かないでしょう。

于 2013-01-27T11:49:57.277 に答える