2012-05-18 2 views
2

내가 좋아하는 변수 타입의 시리즈가 변할 때의 XPath 쿼리는 XML 형식

<area name="DataMap"> 
    <int name="number" nullable="true"> 
     <case var="abc2,abc3,abc5">11</case> 
     <case var="abc4,abc6*">8</case> 
     <case var="data1,xyz7,xyz8">22</case> 
     <case var="data3A,xyz{9},xyz{5A,5B,5C}">24</case> 
     <case var="xyz{6,4A,4B,4C}">20</case> 
     <case var="other01">15</case> 
    </int> 
</area> 

내가 쿼리를 바라고 무엇 인스턴스와 같은 예를 들어 xyz5A는에 매핑됩니다. 쿼리는 24를 반환해야하지만 xml 노드의 해당 참조가 "xyz4A"와 같이 명시 적이거나 "xyz4 *"와 같은 와일드 카드를 사용하거나 위와 같이 중괄호를 사용하면 미리 알 수 없습니다.

그 라인에 문자열이 쿼리를 성공적으로 히트 반환합니다

xpath '/area[@name="DataMap"]/int[@name="number"]/case[contains(@var,"xyz")][contains(@var,"5A")]' 

을 그러나 그것은 또한 잘못된하지 data5A의 히트 반환

xpath '/area[@name="DataMap"]/int[@name="number"]/case[contains(@var,"data")][contains(@var,"5A")]' 

이 XPath는/기타됩니다 위의 일관성없는 (그러나 나는 유효한) xml을 구문 분석하는 쿼리 구문? 와일드 카드와 중괄호 형식에 비해 명시 적 문자열 일치에 대해 쿼리 할 수있는 것 같습니다.

+0

XPath 1.0 또는 XPath 2.0? (2.0에서는 정규 표현식과 '일치'가 도입되었습니다.) –

+0

좋은 지적. 나는 아직도 1.0이라고 생각하는 bash/perl을 사용하고있다. XPath 2.0으로 쿼리하는 실질적인 방법이 있다면, 좋습니다. 예를 들어 Java 라이브러리에 액세스 할 수는 있지만 쿼리 할 필요가있는 모든 시스템에서 확실하지 않습니다. – mmond

답변

1

bash/perl에 속하는 사람은 libxml입니다. libxml은 XPath 2.0을 지원하지 않습니다. libxml/libxslt 및 Perl을 사용하는 XPath/XSLT 2.0에 관한 많은 질문이 있습니다.

XPath 1.0에는 다양성 (내가 인정해야하는 작은 크기)이 string functions이고이를 함께 스택 할 수 있습니다. 나는 약간의 실험을했는데 그 결과를 좋아하지도 않았고 가능한 모든 경우를 다루는 데 성공하지 못했습니다. 당신은 것 "못생긴"과 같이 구성한다 :

... 
or 
(contains(@var, ',xyz{') and 
contains(substring-before(substring-after(@var, ',xyz{'), '}'), '5A') and 
    (contains(substring-before(substring-after(@var, ',xyz{'), '}'), ',5A,') or 
     starts-with(substring-after(@var, ',xyz{'), '5A,') or 
     starts-with(substring-after(@var, ',xyz{'), '5A}') or 
     substring-after(substring-before(substring-after(@var, ',xyz{'), '}'), ',5A') = '')) 

or 
... 

그리고 당신은 substring-* 기능은 일치하는 문자열의 첫 번째 발생 떨어져 작동하는지 깨달을 것입니다 그리고 당신은 더 and의 층과 같은 경우를 처리 할 수 ​​or의 필요 당신 :

<case var="data3A,xyz{9},xyz{5A,5B,5C}">24</case> 
xyz{ 여러가

와 당신이 필요로하는 일을 알 수없는 첫 번째 하나가 될 수 있습니다.

나는 이것이 XML을 가지고 있고 Perl이 좋은 것을 수행하고 텍스트으로 취급한다는 것을 잊어 버린 경우라고 생각합니다. XML 처리 및 데이터 추출을위한 XML 인식 도구가 마음에들만큼 많은 경우 정규 표현식 및 문자열 조작을 위해 설계된 언어로 더 잘 처리 할 수 ​​있습니다.

+0

포괄적 인 솔루션이 좋은 ROI가 아닐 것이라는 것에 동의합니다. Xpath + 도구를 사용하여 수작업으로 예외를 처리 할 수있는 것처럼 정확하게 파싱하는 것이 더 합리적입니다. 의견을 보내 주셔서 감사합니다. – mmond

0

가장 똑똑한 것은 모든 변수를 반복하고 프로그래밍 방식으로 XPath에 요구하지 않고 일치하는 항목을 찾는 것입니다.

나는 그 중괄호에 대해 최소한 몇 가지 생각을하고 있습니다. 불행히도, 그들은 아마도 * 질문에 대해서는 그다지 도움이되지 않습니다.

당신이 .../case[@var =~ /some_regex/], 어쩌면 .../case["xyz4A" =~ to_regex(@var)]를 작성할 수 펄 XPath는 구현이 있다는 것, 그리고 어쩌면 (물론 적절하게 작성 explode_braces 기능 포함) .../case[explode_braces(@var) =~ /(^|,)xyz4A(,|$)/]. 예를 들어 http://www.perlmonks.org/?node_id=831612을 참조하십시오. explode_braces 방법이 첫 번째 대안보다 훨씬 쉽게 작동 할 것으로 기대합니다. 정규 표현식을 꽤 많이 사용합니다.그럼 다시, 당신은 bash-regexes를 사용하는 것, 그리고 perl 정규 표현식으로 변환하는 것은 또한 비교적 간단해야합니다. 그래서 두 번째 아이디어가 효과가 있다면, 당신은 잘 할 수 있습니다.

그래도 작동하지 않는다면 XML 파서에 연결하거나 그 바로 앞에 괄호를 확장하여이 끔찍한 XML 디자인을 수정할 수 있습니까?

$input =~ s/\bvar="([^"]*)"}/'var="'+explode_braces($2)+'"'/eg; 

(또는 미안, 나는 지난 몇 년 동안 많은 펄을 작성하지 않은, 매우 비슷한 뭔가. 또한,이 당신의 XML은 속성 따옴표의 한 유형을 사용하는 가정,하지만 쉽게 해결해야하고, var="이있는 유일한 장소는이 속성에 있으며 훨씬 더 제한이 있습니다.)

+0

크리스토퍼에게 감사드립니다. 폭발적 접근법을 살펴 보겠습니다. – mmond