ãããããããã®åãããŒã«ã䜿çšãããšãéåžžã«è€éãªã³ãŒããäœæã§ããŸãã
scalazã¹ã¿ã€ã«ã®ã¹ããŒããã©ã³ã·ã³ã°ãŸãã¯äžå®åã³ã³ãã¥ãŒãã£ã³ã°ã䜿çšãããšããŠããããã³ãŒããç解ããããšãä¿èšŒãããŸãã
ãã®èšäºã§ã¯ãäœãããã¹ããã«ã€ããŠè©±ããŸãã
Scalaã«ç°ãªãèšèªãåã蟌ãæ¹æ³ã説æããŸãã
XPathãšç§ã¯åã蟌ã¿ãŸããã説æããæ¹æ³ã¯ãæ§æããªãŒãæ§ç¯ã§ãããã¹ãŠã®èšèªã«é©ããŠããŸãã
çç±
Scalaã«ã¯ãJavaã«ããxmlãæäœããããã®ãã¹ãŠã®ããŒã«ã䜿çšããæ©èœããããŸãïŒå€ãã®ããŒã«ããããŸãïŒã ããããã³ãŒãã¯å€ãè¯ãJavaã³ãŒããæãåºãããŸãã ããŸã幞ãã§ã¯ãªãèŠéãã
èšèªæ§æã«çµã¿èŸŒãŸãããã€ãã£ãxmlããããŸãã
scala> <root> | <node attr="aaa"/> | <node attr="111"> text</node> | </root> res0: scala.xml.Elem = <root> <node attr="aaa"/> <node attr="111"> text</node> </root> scala> res0 \\ "node" res1: scala.xml.NodeSeq = NodeSeq(<node attr="aaa"/>, <node attr="111"> text</node>) scala> res1 \\ "@attr" res2: scala.xml.NodeSeq = NodeSeq(aaa, 111)
ããã¯å¹žãã®ããã§ãããéããŸãã ãªã¢ãŒãã§ã®ã¿XPathã«äŒŒãŠããŸãã å°ãè€éãªã¯ãšãªã¯é¢åã§èªã¿ã«ãããªããŸããã
ããããscalaãããçšåºŠç¥ã£ãåŸãäœæè ãæ ¹æ ãªãscalaãã¹ã±ãŒã©ãã«ãªèšèªãšåŒãã§ããªãããšãæããã«ãªããŸããã ãããŠãäœããæ¬ ããŠããå Žåããããè¿œå ã§ããŸãã
èšèªãžã®äŸ¿å©ãªçµ±åã«ãããã¿ã¹ã¯ãå¯èœãªéãXPathã«è¿ã¥ããŸãã
çµæ
ããã§ã®ãã¹ãŠã®éçºïŒ https : //github.com/senia-psm/scala-xpath.git
èŠæ¹
gitãšsbtããŸã ãªãå Žåã¯ãããããã€ã³ã¹ããŒã«ããå¿
èŠãããïŒ git ã sbt ïŒãå¿
èŠã«å¿ããŠããããã·ãæ§æããå¿
èŠããããŸãïŒ git ã sbt -Program FilesïŒx86ïŒ\ SBT \ãã®ãããªãªãã·ã§ã³ã®ããã®ç¹å¥ãªtxtããããŸãïŒã
ãªããžããªã®ã¯ããŒã³ãäœæããŸãã
ãªããžããªïŒscala-xpathïŒããããã©ã«ããŒã«ç§»åãããããžã§ã¯ãã§REPLãéããŸãã
ãŸããå€ãã®äŸã§ã¯ã次ã®ã€ã³ããŒããå®è¡ãããŠãããšæ³å®ãããŠããŸãã
ãªããžããªã®ã¯ããŒã³ãäœæããŸãã
git clone https://github.com/senia-psm/scala-xpath.git
ãªããžããªïŒscala-xpathïŒããããã©ã«ããŒã«ç§»åãããããžã§ã¯ãã§REPLãéããŸãã
sbt console
ãŸããå€ãã®äŸã§ã¯ã次ã®ã€ã³ããŒããå®è¡ãããŠãããšæ³å®ãããŠããŸãã
import senia.scala_xpath.macros._, senia.scala_xpath.model._
äœãšã©ã®ããã«
ç®æšãéæããæ¹æ³ã¯ãç®æšèªäœã«ãã£ãŠäžæã«æ±ºå®ãããŸãã
XPathãDSLãšããŠåã蟌ãããšã¯æããã«å€±æããŸãã ããããªããšãXPathã§ã¯ãªããªããŸãã scalaã®XPathåŒã¯æååãšããŠã®ã¿é 眮ã§ããŸãã
ã€ãŸãïŒ
- ããŒãµãŒã³ã³ãããŒã¿ãŒ ã æ€èšŒã®ããã«æååã解æããå¿ èŠããããŸãã
- ã¹ããªã³ã°è£é ã XPathã«å€æ°ãšé¢æ°ãåã蟌ãããã
- ãã¯ã ã³ã³ãã€ã«æ®µéã§ã®æ€èšŒçšã
ãªããžã§ã¯ãã¢ãã«ãæºåããŸãã
XPath 1.0ä»æ§ãåãäžããŠã scalaã§æžãçŽããŠãã ããã
ã»ãšãã©ãã¹ãŠã®ããžãã¯ã¯ãåã·ã¹ãã ãšscalaã®ç¶æ¿ã¡ã«ããºã ã«ãã£ãŠè¡šçŸãããŸãã äŸå€ã¯ãrequireãä»ããå¶éã®ããã€ãã®å Žæã«ãããŸãã
ããã§ã¯ããã®ãã¡ã€ã«ã®å€éšã§ã¯ã©ã¹ãç¶æ¿ããïŒãŸãã¯ã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ããïŒããšãçŠæ¢ãããsealedãããŒã¯ãŒãã«æ³šç®ãã䟡å€ããããŸãã ç¹ã«ããµã³ãã«ãšæ¯èŒããå Žåããã·ãŒã«ãã䜿çšãããšãã³ã³ãã€ã©ã¯ãã¹ãŠã®å¯èœãªãªãã·ã§ã³ãèæ ®ãããŠããããšã確èªã§ããŸãã
Parsim XPath
ããŒãµãŒã®çŽ¹ä»
ããŒãµãŒã¯ãäžé£ã®èŠçŽ ãåããæåããå ŽåãåŠççµæãšæ®ãã®ã·ãŒã±ã³ã¹ãè¿ãé¢æ°ã§ãã
ãã ãã倱æããçµæã«ã¯ãã倱æããšããšã©ãŒãã®2ã€ã®åœ¢åŒããããŸãã
æ¯Figçã«èšãã°ãããŒãµãŒã¯ã·ãŒã±ã³ã¹ã®äžéšãæåããåã¿ãåãŸãããã®ãç¹å®ã®ã¿ã€ãã®ãªããžã§ã¯ãã«å€æããŸãã
æãåçŽãªããŒãµãŒã¯ãã·ãŒã±ã³ã¹ã®æåã®èŠçŽ ãæå®ã®èŠçŽ ãšçããããšã確èªãããã®èŠçŽ ãæåããçµæãšããŠè¿ãããŒãµãŒã§ãã æ®ããšããŠããã®èŠçŽ ã®ãªãã·ãŒã±ã³ã¹ããããŸãã
èŠçŽ ãããã®ãããªããŒãµãŒãäœæããã«ã¯ãèŠçŽ ãåãå ¥ããacceptã¡ãœããã䜿çšããŸãã ãã®ã¡ãœããã¯æé»çãšããŠå®çŸ©ãããŠãããã³ã³ãã€ã©ãããŒãµãŒã«äŒããšäºæ³ãããèŠçŽ ã«ééããå Žåããã®ã¡ãœããã®ã¢ããªã±ãŒã·ã§ã³ãèŠçŽ ã«è¿œå ããŸãã
æåã®ã·ãŒã±ã³ã¹ã解æãããšããŸãããïŒ
ãããã£ãŠãããŒãµãŒãçµã¿åããããšãã«ãããŒãµãŒãããã¹ãå Žæã«èŠçŽ ãããå Žåããã®ãããªåºæ¬çãªããŒãµãŒãããã«ããããšãç¥ã£ãŠããŸãã
äžè¬ã«ãããã¯æ瀺çã«å®çŸ©ãããå¯äžã®ããŒãµãŒã§ãã
ä»ã®ãã¹ãŠã®ããŒãµãŒã¯ãä»ã®ããŒãµãŒãšçµæå€æã®çµã¿åããã«ãã£ãŠååŸãããŸãã
äºé æŒç®åã¯ãããã§ãã ãandãã®ååã«åŸã£ãŠ2ã€ã®ããŒãµãŒãçµã¿åãããŸãã æåã®ããŒãµãŒãæåããå Žåã«ã®ã¿æåãããã®åŸãæåã®ããŒãµãŒã解æããæ®ãã®2çªç®ã®ããŒãµãŒãæåããŸãã
æ¯urçã«èšãã°ãæåã®ããŒãµãŒãæåã«åœŒã«åã£ããã®ãåã¿ã次ã«2çªç®ã®ããŒãµãŒãæ®ãç©ãé£ã¹ãŸãã
äž¡æ¹ã®ããŒãµãŒã®çµæãå«ãã³ã³ãããŒãçµæãšããŠè¿ãããŸãã
ãã®æ¹æ³ã§ãããŒãµãŒã®ä»»æã®ã»ãããçµã¿åãããããšãã§ããŸãã
ãã®ã³ã³ãããŒã¿ã«ã¯ããã>ããšã<ããã®2ã€ã®å åŒããããŸãã ãããã¯åãããã«æ©èœããŸãããçµã¿åãããããŒãµãŒã®1ã€ã ãã®çµæãè¿ããŸãã
äºé æŒç®åã|ãã ããŸãã¯ãã«åºã¥ãé¢é£ä»ãã å°ãªããšã1ã€ã®çµæãåæå ¥åã§æåããå Žåã¯æåã§ãã æåã®ããŒãµãŒãã倱æããè¿ããå ŽåïŒãšã©ãŒã§ã¯ãªãïŒãåãå ¥åã2çªç®ã®ããŒãµãŒã«ãã£ãŒãããããšããŸãã
æ åœè ã·ãŒã±ã³ã¹ã ããŒãµãŒãmyParserããããå ŽåããrepïŒmyParserïŒãã䜿çšããŠäœæãããããŒãµãŒã¯ãå ¥åããæåã®å€±æããã¢ããªã±ãŒã·ã§ã³ãžã®ãmyParserãã®å©ããåããŠããã€ããããŸãã ãã¹ãŠã®ããã€ããã®çµæã¯ãã³ã¬ã¯ã·ã§ã³ã«çµåãããŸãã
空ã§ãªãçµæã³ã¬ã¯ã·ã§ã³ïŒrep1ïŒããã³åºåãã·ãŒã±ã³ã¹ïŒrepsepïŒã«ã¯ãé¢é£ããå€æããããŸã
解æã®çµæã«å¯ŸããŠå€æãå®è¡ããå¿ èŠãããå Žåã¯ã^^^ã^^ãªã©ã®æŒç®åã圹ç«ã¡ãŸã
^^^ã¯çµæãæå®ãããå®æ°ã«å€æŽãã^^ã¯æå®ãããé¢æ°ã䜿çšããŠçµæãå€æããŸãã
ãã ãã倱æããçµæã«ã¯ãã倱æããšããšã©ãŒãã®2ã€ã®åœ¢åŒããããŸãã
æ¯Figçã«èšãã°ãããŒãµãŒã¯ã·ãŒã±ã³ã¹ã®äžéšãæåããåã¿ãåãŸãããã®ãç¹å®ã®ã¿ã€ãã®ãªããžã§ã¯ãã«å€æããŸãã
æãåçŽãªããŒãµãŒã¯ãã·ãŒã±ã³ã¹ã®æåã®èŠçŽ ãæå®ã®èŠçŽ ãšçããããšã確èªãããã®èŠçŽ ãæåããçµæãšããŠè¿ãããŒãµãŒã§ãã æ®ããšããŠããã®èŠçŽ ã®ãªãã·ãŒã±ã³ã¹ããããŸãã
èŠçŽ ãããã®ãããªããŒãµãŒãäœæããã«ã¯ãèŠçŽ ãåãå ¥ããacceptã¡ãœããã䜿çšããŸãã ãã®ã¡ãœããã¯æé»çãšããŠå®çŸ©ãããŠãããã³ã³ãã€ã©ãããŒãµãŒã«äŒããšäºæ³ãããèŠçŽ ã«ééããå Žåããã®ã¡ãœããã®ã¢ããªã±ãŒã·ã§ã³ãèŠçŽ ã«è¿œå ããŸãã
æåã®ã·ãŒã±ã³ã¹ã解æãããšããŸãããïŒ
def elementParser: Parser[Char] = 'c' // def elementParser: Parser[Char] = accept('c') //
ãããã£ãŠãããŒãµãŒãçµã¿åããããšãã«ãããŒãµãŒãããã¹ãå Žæã«èŠçŽ ãããå Žåããã®ãããªåºæ¬çãªããŒãµãŒãããã«ããããšãç¥ã£ãŠããŸãã
äžè¬ã«ãããã¯æ瀺çã«å®çŸ©ãããå¯äžã®ããŒãµãŒã§ãã
ä»ã®ãã¹ãŠã®ããŒãµãŒã¯ãä»ã®ããŒãµãŒãšçµæå€æã®çµã¿åããã«ãã£ãŠååŸãããŸãã
ããŒãµãŒãçµã¿åããã
åã®ããã«ãã
å®éãscalaã«ã¯æŒç®åã¯ãããŸãããããããç¥ã£ãŠããã°ãããããããŒãµãŒã«ã€ããŠè©±ãå¿
èŠã¯ãããŸããã
äºé æŒç®åã¯ãããã§ãã ãandãã®ååã«åŸã£ãŠ2ã€ã®ããŒãµãŒãçµã¿åãããŸãã æåã®ããŒãµãŒãæåããå Žåã«ã®ã¿æåãããã®åŸãæåã®ããŒãµãŒã解æããæ®ãã®2çªç®ã®ããŒãµãŒãæåããŸãã
æ¯urçã«èšãã°ãæåã®ããŒãµãŒãæåã«åœŒã«åã£ããã®ãåã¿ã次ã«2çªç®ã®ããŒãµãŒãæ®ãç©ãé£ã¹ãŸãã
äž¡æ¹ã®ããŒãµãŒã®çµæãå«ãã³ã³ãããŒãçµæãšããŠè¿ãããŸãã
parser1 ~ parser2
ãã®æ¹æ³ã§ãããŒãµãŒã®ä»»æã®ã»ãããçµã¿åãããããšãã§ããŸãã
ãã®ã³ã³ãããŒã¿ã«ã¯ããã>ããšã<ããã®2ã€ã®å åŒããããŸãã ãããã¯åãããã«æ©èœããŸãããçµã¿åãããããŒãµãŒã®1ã€ã ãã®çµæãè¿ããŸãã
äºé æŒç®åã|ãã ããŸãã¯ãã«åºã¥ãé¢é£ä»ãã å°ãªããšã1ã€ã®çµæãåæå ¥åã§æåããå Žåã¯æåã§ãã æåã®ããŒãµãŒãã倱æããè¿ããå ŽåïŒãšã©ãŒã§ã¯ãªãïŒãåãå ¥åã2çªç®ã®ããŒãµãŒã«ãã£ãŒãããããšããŸãã
æ åœè ã·ãŒã±ã³ã¹ã ããŒãµãŒãmyParserããããå ŽåããrepïŒmyParserïŒãã䜿çšããŠäœæãããããŒãµãŒã¯ãå ¥åããæåã®å€±æããã¢ããªã±ãŒã·ã§ã³ãžã®ãmyParserãã®å©ããåããŠããã€ããããŸãã ãã¹ãŠã®ããã€ããã®çµæã¯ãã³ã¬ã¯ã·ã§ã³ã«çµåãããŸãã
空ã§ãªãçµæã³ã¬ã¯ã·ã§ã³ïŒrep1ïŒããã³åºåãã·ãŒã±ã³ã¹ïŒrepsepïŒã«ã¯ãé¢é£ããå€æããããŸã
çµæãå€æãã
解æã®çµæã«å¯ŸããŠå€æãå®è¡ããå¿ èŠãããå Žåã¯ã^^^ã^^ãªã©ã®æŒç®åã圹ç«ã¡ãŸã
^^^ã¯çµæãæå®ãããå®æ°ã«å€æŽãã^^ã¯æå®ãããé¢æ°ã䜿çšããŠçµæãå€æããŸãã
ããŒãµãŒã®çµã¿åããïŒããã³w3cä»æ§ã®ãªãã©ã·ãŒïŒã«ãããããããããšãªãããŒãµãŒãäœæã§ããŸãã
å®éãä»æ§ã2åæžãæããŠããŸãã å¯äžã®å€§ããªéãã¯ãååž°çãªå®çŸ©ãã埪ç°ãå®çŸ©ïŒrepããã³repsepïŒã«çœ®ãæããããšã§ãã
äŸïŒ
ä»æ§ïŒ
[15] PrimaryExpr :: = VariableReference | 'ïŒ' Expr 'ïŒ' | ãªãã©ã« | æ° | é¢æ°åŒã³åºã
ããŒãµãŒ ïŒ
def primaryExpr: Parser[PrimaryExpr] = variableReference | `(` ~> expr <~ `)` ^^ { GroupedExpr } | functionCall | number | literal
å¯äžã®æ¡ä»¶ã¯ãæããå³å¯ãªãããŒãµãŒãã|ããä»ããŠãŠããªã³ã«å ¥ãããšãä¿èšŒããå¿ èŠãããããšã§ãã æ®ãã®åã«ã ãã®äŸã§ã¯ãé¢æ°ã®ååã®è§£æã«æåããã ãã§ãfunctionCallãæåããå Žåã«ãªãã©ã«ãæããã«æåããŸãããããã£ãŠããªãã©ã«ãå ã«é 眮ãããšãåã«functionCallã«å°éããŸããã
ããŒãµãŒã®ã»ããå šäœã150è¡ã«åãŸãããªããžã§ã¯ãã¢ãã«ã®å®çŸ©ãããå€§å¹ ã«çããªããŸãã
ããã¯ã¹å€æ°
åŒã«å€æ°ãè¿œå ããã«ã¯ãããŒãžã§ã³2.10ã§ç»å Žããæååè£éã¡ã«ããºã ã䜿çšããŸãã
ã¡ã«ããºã ã¯éåžžã«ç°¡åã§ããæå¹ãªã¡ãœããåã§ããåã®è¡ïŒã¹ããŒã¹ãªãïŒã«ééãããšãã³ã³ãã€ã©ã¯åçŽãªå€æãå®è¡ããŸãã
t"strinf $x interpolation ${ obj.name.toString } " StringContext("strinf ", " interpolation ", " ").t(x, { obj.name.toString })
æååã¯ãå€æ°ãšåŒã®åºçŸã«ãã£ãŠæçã«åå²ãããStringContextãã¡ã¯ããªã¡ãœããã«æž¡ãããŸãã æååã®åã®ååã¯ã¡ãœããã®ååãšããŠäœ¿çšããããã¹ãŠã®å€æ°ãšåŒã¯ãã©ã¡ãŒã¿ãŒãšããŠãã®ã¡ââãœããã«æž¡ãããŸãã
ããããsãããfããªã©ã®ã¡ãœããã§çµããå ŽåãStringContextã«ãªãã¡ãœããã«ã€ããŠãã³ã³ãã€ã©ã¯æé»çãªã¯ã©ã¹ãã€ãŸãç®çã®ã¡ãœãããå«ãStringContextã®ã©ãããŒãæ¢ããŸãã ãã®ãããªæ€çŽ¢ã¯scalaã®äžè¬çãªã¡ã«ããºã ã§ãããæååè£éã«ã¯çŽæ¥é©çšãããŸããã
æçµã³ãŒãïŒ
new MyStringContextHelper(StringContext("strinf ", " interpolation ", " ")).t(x, { obj.name.toString })
ããããããŒãµãŒã¯ã©ãã§ããïŒ é£ç¶ããæååã¯ãªããªããŸããã ãããŠãæåã®ã·ãŒã±ã³ã¹ãšäœãä»ã®ãã®ããããŸãã
ãã¹ãŠã®äœæ¥ã¯ææ°ŽãããŠããŸããïŒ
ããã¯ãæåã®ã·ãŒã±ã³ã¹ã ãã§ãªã解æããæ©èœã®æçšæ§ãæããã«ãªãå Žæã§ãã
äžé£ã®æåãšä»ã®ãã®ããããŸãïŒããã«ã€ããŠã¯åŸã§èª¬æããŸãïŒã ããã¯ãã©ã¡ããã®æŠå¿µã§èª¬æãããŠããŸãã ããã«ã¯ãã·ã°ã«ã©ãã®ããããã«é¢ãã ããã€ãã® èšäºã翻蚳ãããŠããŸã ã
ããŒãµãŒã®èœåãæ倧éã«æŽ»çšããã«ã¯ãããã€ãã®è£å©ããŒã«ãäœæããã ãã§ãã ç¹ã«ãCharãStringãRegexãã察å¿ããããŒãµãŒãžã®å€æã
å¿ èŠãªãã¹ãŠã®ããŒã«ã¯æ¬¡ã®ãšããã§ãïŒ BothParsers ã æœè±¡åRã«æ³šæãæã䟡å€ããããŸããããã«ã€ããŠã¯æ³å®ãããŠããªãããããã®ããŒã«ãããã¯å€æ°ãè¡šãããã®ä»¥åã¯æªç¥ã®æ¹æ³ã«é©ããŠããŸãã
ç·šéã«å¹²æžãã
ç§ã®æèŠã§ã¯ããã¯ãã«é¢ããããã¥ã¡ã³ããšåŠ¥åœãªäŸã¯ã»ãšãã©ãããŸããã ããããã ãããšãã£ãŠããã¯ããšã¯äœãããŸããã¯ããäœãé£ã¹ãã®ããç¶²çŸ çã«èª¬æããã€ããã¯ãããŸããã
ãŸãããã¯ãããŒã¯ãŒãã䜿çšããŠå®è£ ãããã¡ãœãããã³ã³ãã€ã©ãæ€åºãããšãã«ãã¯ããåŒã³åºããããã¯ãå®è£ ãæ°ããäœæãããæ§æããªãŒãè¿ãå¿ èŠãããããšãç¥ã£ãŠããå¿ èŠããããŸãã
æãåçŽãªäŸã®ããã«ã©ã®ãããªããªãŒãäžããã¹ããèŠãŠã¿ãŸãããïŒ
scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> showRaw(reify( "str" -> 'symb )) res0: String = Expr(Apply(Select(Apply(Select(Ident(scala.Predef), newTermName("any2ArrowAssoc")), List(Literal(Constant("str")))), newTermName("$minus$greater")), List(Apply(Select(Ident(scala.Symbol), newTermName("apply")), List(Literal(Constant("symb")))))))
ãã®ãããªèªåãæ§ç¯ããã«ã¯ãããããªæ¬²æ±ã¯ãããŸããã
scalaãæäœæ¥ãªãã§ã¿ã€ãã³ã°ãä¿åã§ããããšãèŠãŠã¿ãŸãããã
äžæ¹ã§ãå€ãã§ã¯ãããŸããïŒãªãã©ã«ã¡ãœãããããã¯ãããã€ãã®éããããåºæ¬åãã®ã»ãããæ§æããªãŒã«å€æãããã¹ãŠã®æåäœæ¥ãè¡ãreifyãå¯èœã«ããŸãããåãããªãŒã®åœ¢åŒã§å€éšããå€æ°ãè¿œå ããå Žåã®ã¿æ¬¡ã«ããã®ããªãŒã®spliceã¡ãœããã䜿çšããŸãããã®ã¡ãœããã¯ãçµæã®ã¿ã€ãTãæã€æ°ããããªãŒã®äžéšãšããŠãã¿ã€ãExpt [T]ã®åŒãåã蟌ããšããèŠæãå ·äœçã«éç¥ããããã«èšèšãããŠããŸãã
äžæ¹ããããã®æ¹æ³ã§ååã§ãã è¿œå ã¯å©çšå¯èœãªãã®ã«åºã¥ããŠæžãããšãã§ããŸãã
ãã¯ãèªäœã«ãã£ãŠåŠçãããè£éãè¿œå ããããšã¯éåžžã«ç°¡æœã§ãã
implicit class XPathContext(sc: StringContext) { def xp(as: Any*): LocationPath = macro xpathImpl }
ãã¯ãåŠçé¢æ°ã¯æ¬¡ã®ããã«å®£èšãããŸãã
def xpathImpl(c: Context)(as: c.Expr[Any]*): c.Expr[LocationPath]
ã©ãããå€æ°ãååŸãããã¯æ確ã§ãããæååãååŸããæ¹æ³ã¯ïŒ
ãããè¡ãã«ã¯ãã³ã³ããã¹ãã䜿çšããŠé¢æ°ããèŠããããšãã§ããŸãã ã€ãŸããåšããèŠãŠãã ããã
ããæ£ç¢ºã«ã¯ãã¿ãŒã²ããXPã¡ãœãããåŒã³åºãããåŒãèŠãŠãã ããã
ããã¯c.prefixã䜿çšããŠå®è¡ã§ããŸãã
ããããããã«ã¯äœãèŠã€ãããŸããïŒ StringContextïŒ "strinf"ã "interpolation"ã ""ïŒã®åœ¢åŒã®åŒãå¿ èŠã§ããããšã以åã«è¿°ã¹ãããŸããã
察å¿ããããªãŒãèŠãŠã¿ãŸãããïŒ
scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> showRaw(reify(StringContext("strinf ", " interpolation ", " "))) res0: String = Expr(Apply(Select(Ident(scala.StringContext), newTermName("apply")), List(Literal(Constant("strinf ")), Literal(Constant(" interpolation ")), Literal(Constant(" ")))))
ãããããããããã«ããã¹ãŠã®è¡ãæ瀺çãªåœ¢åŒã§ååŸã§ããŸãã
val strings = c.prefix.tree match { case Apply(_, List(Apply(_, ss))) => ss case _ => c.abort(c.enclosingPosition, "not a interpolation of XPath. Cannot extract parts.") } val chars = strings.map{ case c.universe.Literal(Constant(source: String)) => source.map{ Left(_) } case _ => c.abort(c.enclosingPosition, "not a interpolation of XPath. Cannot extract string.") }
ããããå ¥ãå£ã ããå€ãã£ãããã§ã¯ãããŸããã ããŒãµãŒã®çµæã¯ãªããžã§ã¯ãã¢ãã«ã®ãªããžã§ã¯ãã§ã¯ãªããªããŸããå€ã§ã¯ãªãc.Expr [Any]ã®åœ¢åŒã®ãã©ã¡ãŒã¿ãŒã«åºã¥ããŠæ§ç¯ããããšã¯ã§ããŸããã
ããã«å¿ããŠããŒãµãŒãå€æŽããŸãã ãã®çµæãå€éšå€æ°ãå°ãªããšãäœããã®åœ¢ã§åºçŸããå¯èœæ§ãããå ŽåãããŒãµãŒã¯Tãè¿ãããšã¯ã§ããŸããããc.Expr [T]ãè¿ãå¿ èŠããããŸãã éåºæ¬åãã察å¿ããExprãžã®å€æã®ããã«ã䜿çšå¯èœãªãã®ã«åºã¥ããŠè£å©ãªãã©ã«ã¡ãœãããäœæããŸãã次ã«äŸã瀺ããŸãã
def literal(name: QName): lc.Expr[QName] = reify{ QName(literal(name.prefix).splice, literal(name.localPart).splice) }
ãã®ãããªãã¹ãŠã®é¢æ°ã®åçã¯éåžžã«åçŽã§ããåŒæ°ãããªãåºæ¬çãªéšåã«è§£æããreifyå ã§åæ§æããŸãã
ããã«ã¯æ©æ¢°çãªäœæ¥ãå¿ èŠã§ãããããŒãµãŒã¯ããã»ã©å€ãããŸããã
æåŸã®ã¹ãããã¯ãå ¥åã§å€æ°ã解æã§ããããã€ãã®ããŒãµãŒã®å°å ¥ã§ãã
以äžã¯ãå€æ°ãåã蟌ãããã®ããŒãµãŒã§ãã
accept("xc.Expr[Any]", { case Right(e) => e } ) ^? ({ case e: xc.Expr[BigInt] if confirmType(e, tagOfBigInt.tpe) => reify{ CustomIntVariableExpr(VariableReference(QName(None, NCName(xc.literal(nextVarName).splice))), e.splice) } case e: xc.Expr[Double] if confirmType(e, xc.universe.definitions.DoubleClass.toType) => reify{ CustomDoubleVariableExpr(VariableReference(QName(None, NCName(xc.literal(nextVarName).splice))), e.splice) } case e: xc.Expr[String] if confirmType(e, xc.universe.definitions.StringClass.toType) => reify{ CustomStringVariableExpr(VariableReference(QName(None, NCName(xc.literal(nextVarName).splice))), e.splice) } }, e => s"Int, Long, BigInt, Double or String expression expected, $e found." )
æåã®ããŒãµãŒ "acceptïŒ" xc.Expr [Any] "ã{case RightïŒeïŒ=> e}ïŒ"ã¯éåžžã«åçŽã§ã-ããªãŒãæã€Rightã³ã³ãããåãå ¥ãããã®ããªãŒãè¿ããŸãã
ããã«å€æãè¡ããšããã®å€æ°ã3ã€ã®ç®çã®åã®ãããããšããŠäœ¿çšã§ãããã©ãããå€æããããã®ãããªäœ¿çšã«å€æãããŸãã
ãã®çµæã次ã®åäœãçºçããŸãã
scala> val xml = <book attr="111"/> xml: scala.xml.Elem = <book attr="111"/> scala> val os = Option("111") os: Option[String] = Some(111) scala> xml \\ xp"*[@attr = $os]" // Option[String] <console>:16: error: Int, Long, BigInt, Double or String expression expected, Expr[Nothing](os) found. xml \\ xp"*[@attr = $os]" ^ scala> xml \\ xp"*[@attr = ${ os.getOrElse("") } ]" // String res1: scala.xml.NodeSeq = NodeSeq(<book attr="111"/>)
ãŸãããšã©ãŒã¡ãã»ãŒãžãããã«æ¹åããå¿ èŠãããå Žåãå€æ°ã¯æ¢ã«éåžžã«äŸ¿å©ã«çµã¿èŸŒãŸããŠããŸãã
é¢æ°ãåã蟌ãã«ã¯å€ãã®ã³ãŒãïŒ23ã®ãªãã·ã§ã³ã0ãã22ã®ãã©ã¡ãŒã¿ãŒã®ãªãã·ã§ã³çšïŒãå¿ èŠã§ãããAnyã®ã¿ãåãå ¥ããå¿ èŠããããããããŸã䟿å©ã§ã¯ãããŸããããåºæ¬çã«NodeListãæ¥ãŸãïŒãã ããè¡ãæ¥ãããDoubleã«ãªãå¯èœæ§ããããŸãïŒïŒ
scala> import org.w3c.dom.NodeList import org.w3c.dom.NodeList scala> val isAllowedAttributeOrText = (_: Any, _: Any) match { // - , | case (a: NodeList, t: NodeList) if a.getLength == 1 && t.getLength == 1 => | a.head.getTextContent == "aaa" || | t.head.getTextContent.length > 4 | case _ => false | } isAllowedAttributeOrText: (Any, Any) => Boolean = <function2> scala> val xml = <root attr="11111" ><inner attr="111" /><inner attr="aaa" >inner text</inner> text </root> xml: scala.xml.Elem = <root attr="11111"><inner attr="111"/><inner attr="aaa">inner text</inner> text </root> scala> xml \\ xp"*[$isAllowedAttributeOrText(@attr, text())]" res0: scala.xml.NodeSeq = NodeSeq(<root attr="11111"><inner attr="111"/><inner attr="aaa">inner text</inner> text </root>, <inner attr="aaa">inner text</inner>)
ããã§ã¯ãXPathæ§æããæåã®æ··ä¹±ãååŸããŸããïŒå€æ°ã®ä»£ããã«$ {ä»»æã®ã³ãŒã}ã®åœ¢åŒã®åŒãèšè¿°ããå¯èœæ§ãé€ãïŒ-å®è£ ãããé¢æ°ã®åã«ãã«ãä»ããå¿ èŠããããŸãã
ã¡ãœããã®å®è£
åœç¶ãscala.xml.NodeSeqã®ã¡ãœããã\ããšã\\ãèªäœã¯éæ³ã«ãã£ãŠçŸããã®ã§ã¯ãªããã¢ãã«ã®ããã±ãŒãžãªããžã§ã¯ãã®æé»ã¯ã©ã¹ã䜿çšããŠè¿œå ãããŸã ã
åæ§ã®ã¡ãœãããorg.w3c.dom.Nodeããã³NodeListã«çµã¿èŸŒãŸããŠããŸã ã
ãŸããçµæã®XPathãé©çšãããšãç¹å®ã®åé¡ãçºçããŸãã
æªè§£æ±ºã®åé¡
java.lang.System.setSecurityManagerïŒnullïŒ ãåãé€ããŸãã com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImplã®å®è£ ããå€æãããšãã«ã¹ã¿ã é¢æ°ãã³ãã©ãŒãè¿œå ããä»ã®æ¹æ³ã¯ãããŸããã
ã³ã³ãã€ã«æ®µéã§ã®ãšã©ãŒã¯æ¹åãå¿ èŠã§ãã
é¢æ°ãæ£ããæå®ãããŠããªãå Žåããšã©ãŒã¡ãã»ãŒãžã¯å®ç§ã§ãïŒã³ã³ãã€ã©ã®åŠ¥åœæ§ã«å¯Ÿããå¥ã®è³èŸïŒïŒ
scala> xml \\ xp"*[$isAllowedAttributeOrText(@attr)]" <console>:1: error: type mismatch; found : (Any, Any) => Boolean required: Any => Any xml \\ xp"*[$isAllowedAttributeOrText(@attr)]" ^
ãã®åŸãä»ã®ãã¹ãŠã®ãšã©ãŒã«ã€ããŠã¯ãæšæºã®ã¡ãã»ãŒãžåœ¢åŒã¯å°éããããäœçœ®ã¯è¡ã®å§ãŸãã瀺ããŸãã
åã®åé¡ãšã¯ç°ãªãããã®åé¡ã¯å®å šã«è§£æ±ºã§ããŸãã
scala.xmlã䜿çšãããšãã®ããã©ãŒãã³ã¹ã«ã¯ãå€ãã®èŠæããããŸãã å®éãscala.xmlããw3c.domãžã®å€æã¯ãæåã«æååãä»ããŠè¡ããã次ã«éã«è¡ãããŸãã
å¯äžå¯èœãªè§£æ±ºçã¯ãXPathãèªåã§åŠçããããšã§ãã
åæã«ãããã¯ããŸã䟿å©ã§ã¯ãªãé¢æ°ã®ã¿ã€ãã³ã°ãåãé€ããŸãã
w3c.domã®ããã©ãŒãã³ã¹ã¯ãããã«æ¹åã§ããŸãã XPathã¯çŸåšãæååããã³ã³ãã€ã«ãããŠããŸãããæ¢è£œã®ãªããžã§ã¯ãã¢ãã«ããããŸãã ãªããžã§ã¯ãã¢ãã«éã§å€æãããšãXPathã®äœæãå€å°éããªããŸãã
ãããã«
XPathã¯æ·±å»ãªåé¡ãå¶éãªãã«scalaã«çµ±åã§ããŸãã
çŸåšã®ã¹ã³ãŒãã®å€æ°ãšé¢æ°ã¯ãä»æ§ã§èš±å¯ãããŠããéãæå¹ã§ãã
w3c.domã§äœ¿çšããããã€ãã®æ¹åãå ããå Žåãã³ã³ãã€ã«äžã«åŒã解æãããããããããªå éãå¯èœã§ãã
ãã¹ãŠãã¯ããã«ç°¡åã§ãã äžèŠãããšæãããŸãã
æåã¯ãã³ã³ãã€ã«ã«åã蟌ããšããã¢ã€ãã¢èªäœãå°çãåŒãèµ·ãããŸãã çµæã¯æå°éã®åŽåã§éæãããŸãã
ã¯ããã³ã³ãã€ã©APIã¯ã¡ã€ã³ã©ã€ãã©ãªãããã¯ããã«æªãããã¥ã¡ã³ãã§ãããè«ççã§ç解ããããã§ãã
ã¯ããIDEAã¯ãã¹äŸååãããç解ããŠããŸããããã³ã³ãã€ã©APIãå«ãéåžžã«äŸ¿å©ãªããã²ãŒã·ã§ã³ãæäŸããæé»çãªå€æãèæ ®ããŸãã