IntelliJ의 structural search를 이용해 xml 의 특정 attribute 이름 바꾸기
며칠동안 나를 괴롭히던 난제를 해결했다.
풀고싶던 문제는 intellij(Android Studio) 에서 특정 tag의 특정 attribute의 이름을 손쉽게 바꾸는 방법은 무엇인가! 이다.
예를 들어 안드로이드 프로젝트의 모든 레이아웃 xml 파일을 뒤져
<mytag ... myns:title="abc"></mytag>
이런 녀석들을 찾아서
<mytag ... myns:mytitle="abc"></mytag>
이렇게 고치는 작업을 한방에 하는 방법이다. 이걸 왜 해야하냐면, 사용하고싶은 library 프로젝트에서 사용중인 custom view의 custom attribute 를 원래 프로젝트에서 이미 사용중이라면 원래 프로젝트의 custom attribute를 바꾸는 수 밖에 없기 때문이다.
IntelliJ 에는 structural search and replace 라는 멋진 기능이 있다. 막 명령어 찾아서 try { } catch 로 감싸는 등의 마술을 부릴 수 있는 도구이다. 다행히 java 뿐 아니라 xml 컨텍스트도 제공한다. 딱 하나 문제가 있는데, 사용하기가 매우매우 복잡해. ㅠㅠ
내가 하고싶은 검색 & 변환 작업은 다음과 같다.
tag 중 mytag 를 찾는다.
이 중 앞쪽 namespace 별칭을 불문하고 특정 속성을 찾는다 (ex. my:title or myns:title )
이제 namespace 별칭은 유지하고선 속성 이름만 바꿔놓는다. 속성값도 그대로 유지한다. (ex. my:title="abc" -> my:myTitle="abc", myns:title="anc" -> myns:myTitle="abc")
별로 어려워보이지 않지만 이틀동안 삽질을 했다. -_-;; 수작업으로 했어도 이미 했겠지만 이놈의 개발자병 때문에 방법을 찾아내느라 고생을 했네.
결론부터 말하면
search template: <$tag$ $attr$="$val$"/>
replace template: $result$
Edit variables... 를 누르면 나오는 대화상자에는
tag: Text/regexp 에 mytag 입력, min 과 max count 모두 1로 설정
attr: .*:title 입력, min 은 1, max 는 unlimited로 설정 , 맨 밑의 target of the search 체크
val: min 은 1, max 는 unliimited로 설정
result: Script text를 다음과 같이 입력 __context__.namespacePrefix + ":myTitle=\""+ __context__.value+"\""
다른 조합도 가능한지 모르겠지만, 이미 너무 지쳐서 알고싶지 않다.
저 __context__ 가 대체 뭔가는 신들린 구글링으로 XmlAttributeImpl라는 걸 찾아냈다. 그러니 다른 속성을 사용하고 싶다면 위 코드에서 속성쪽을 찾아보세요.
자, 이제 검색을 누르면 검색 목록에 이쁘게 xml 중 속성 이름들이 나오고, "Preview Replacement" 를 누르면 namespace prefix가 이쁘게 박힌 결과물이 보일것이다.
야호!
참고로 structural search는 꽤 느리기 때문에 큰 프로젝트라면 찾고싶은 파일들의 scope를 잘 조정해두길 권한다.









