2008-11-06 3 views
3

편집 : 또한 ESXLT 함수에 액세스 할 수 있습니다.XPATH 또는 XSL은 사용자 지정 비교를 사용하여 두 노드 집합과 일치합니다.

두 개의 문자열 토큰 세트가 있습니다. 한 세트는 다음과 같은 값을 포함합니다 :

/Geography/North America/California/San Francisco 
/Geography/Asia/Japan/Tokyo/Shinjuku 

다른 세트는 다음과 같은 값을 포함합니다 :

/Geography/North America/ 
/Geography/Asia/Japan/ 

내 목표는 둘 사이에 "일치"를 찾는 것입니다. 세트 1의 문자열이 세트 2의 문자열로 시작하는 경우 일치가 발생합니다. 예를 들어, /지리학/북미/캘리포니아/샌프란시스코/지리/북미/ 사이에서 일치가 발생합니다. 세트 1의 문자열은 세트 2의 문자열로 시작합니다.

제 3 자 확장을 사용하여 와일드 카드를 사용하여 문자열을 비교할 수 있습니다. Xpath 내에서 정규식을 모두 사용할 수도 있습니다.

제 문제는 어떻게 두 세트의 모든 노드 사이에서 함수를 사용하여 선택하려면 Xpath를 구조합니까? XSL도 실행 가능한 옵션입니다.

이 XPATH :

count($set1[.=$set2]) 

이 SET1 및 설정 2 사이의 교차점의 수를 산출 겠지만,이 1 대 1 비교입니다. 노드를 비교하는 다른 방법을 사용할 수 있습니까?

편집 : 나는이 효과를 얻었지만 동일한 타사 확장을 사용하여 속임수를 사용하고 있습니다. 나는 아직도 다른 방법에 관심이있다.

+0

위의 예에서 일치하는 항목 수를 원하십니까? 따라서 위의 값은 2를 반환해야합니까? –

+0

예, 주어진 예제에서 개수는 2 여야합니다. –

+0

하나의 XPath식이 유일한 옵션입니까? XSLT가 수용 가능합니까? – ChuckB

답변

2

이 :

<xsl:variable name="matches" select="$set1[starts-with(., $set2)]"/> 

텍스트 값 $의 설정 2에서 노드의 텍스트 값으로 시작 $set1의 모든 노드를 포함하는 노드 집합에 $matches을 설정합니다. 그게 니가 찾고있는거야, 맞지?

편집 :

글쎄, 나는 이것에 대해 단지 틀렸다. 이유가 여기 있습니다.

starts-with은 둘 모두에 대한 두 개의 인수가 문자열이어야합니다. 그렇지 않은 경우 함수를 평가하기 전에 문자열로 변환합니다.

노드 집합을 인수 중 하나로 지정하면 노드 집합의 문자열 값을 사용합니다.이 값은 집합의 첫 번째 노드의 텍스트 값입니다. 따라서 위의 경우 $set2은 검색되지 않습니다. 목록의 첫 번째 노드 만 검사되고 따라서 술어는 $set2의 첫 번째 노드 값으로 시작하는 $set1의 노드를 찾습니다.

내가 잘못 인도했기 때문에 (나는 지난 몇 일을 많이 사용하고있다)이 패턴 가하는 일 :

<xsl:variable name="hits" select="$set1[. = $set2]"/> 

그러나 술어는 노드 집합 사이의 비교를 사용하지 텍스트 값 사이.

이렇게하는 가장 좋은 방법은 조건자를 중첩하는 것입니다. 즉, "$set1에있는 모든 노드를 찾기 위해 $set2에 값이있는 노드가 있고 ..."여기에 XPath가 나옵니다. 무엇부터 시작하니?

<xsl:variable name="matches" select="$set1[$set2[starts-with(?, .)]]"/> 

은 현재 외부 술어에 의해 테스트되고 노드를 반환합니다 ?을 위해 쓸 수있는 표현이 없다 : 당신이 쓰고 싶은 것은 같은 것입니다. 그 결과 나무 조각으로 평가하기 때문에

<xsl:variable name="matches"> 
    <xsl:for-each select="$set1"> 
    <xsl:if test="$set2[starts-with(current(), .)]"> 
     <xsl:copy-of select="."/> 
    </xsl:if> 
    </xsl:for-each> 
</xsl:variable> 

매우 만족스러운 해결책이 아니다 (. I 않는 한이 눈부시게 분명 뭔가를 누락)

당신이 원하는 것을 얻으려면, 당신은 개별적으로 각 노드를 테스트해야 노드 집합이 아닙니다. XPath 표현식에서 변수를 사용하려면 확장 기능 (예 : msxsl:node-set)을 사용하여 RTF를 노드 집합으로 변환해야합니다.

+0

예! 이 얼마나 단순하고 우아한 솔루션. 이것은 내가 필요한 것입니다 - 대단히 감사합니다! –

+0

ChuckB의 게시물이 보여준 것처럼 너무 빨리 말했습니다. 다행히도 제 3 자의 확장 기능을 사용하면이 문제를 다른 방법으로 해결할 수 있습니다. –

+0

Robert, 일치 횟수 계산을위한 간단하고 순수한 XSLT 1.0 솔루션 (확장 프로그램 필요 없음)이 있습니다. 내 대답을 보라. –

-1

나는 XPath를 위와 같이 만들 수 없다고 생각합니다. 나는 두 nodesets 초기화 다음 XML 문서에서 시작 :이 스타일은 로버트의 솔루션을 구현한다고 생각

<?xml version="1.0"?> 
<sets> 
    <set> 
    <text>/Geography/North America/California/San Francisco</text> 
    <text>/Geography/Asia/Japan/Tokyo/Shinjuku</text> 
    </set> 
    <set> 
    <text>/Geography/North America/</text> 
    <text>/Geography/Asia/Japan/</text> 
    </set> 
</sets> 

,하지만 난 단지 '1'의 카운트 수 :

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output method="text"/> 

    <xsl:template match="/"> 
    <xsl:variable name="set1" select="sets/set[1]/text/text()"/> 
    <xsl:variable name="set2" select="sets/set[2]/text/text()"/> 
    <xsl:value-of select="count($set1[starts-with(., $set2)])"/> 
    <xsl:text> 
</xsl:text> 
    </xsl:template> 

</xsl:stylesheet> 

내가 한을 재귀 템플릿을 사용하는 스타일 시트를 작성하고 주어진 입력 문서로 '2'의 정확한 수를 산출하지만 Robert의 대답보다 훨씬 덜 우아합니다. XPath가 작동하도록 할 수만 있다면 언제나 배우고 싶을 것입니다.

0

로버트의 마지막 xsl:variable은 일치하는 텍스트 값이 포함 된 결과 트리 조각을 얻는 데 적합하지만 XSLT 1.0에 대한 EXSLT 또는 MS 확장을 사용하여 RTF를 노드 집합으로 변환하지 않으면 일치하는 텍스트 노드의 개수를 가져옵니다. 여기

내가 설정 한 텍스트 노드의 수를 제공하는 준 샘플 입력 문서를 통해 재발 내 이전 응답에 언급 된 XSLT 스타일 시트되는 세트 2 경기의 일부 또는 전부의 노드 :

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output indent="yes" method="text"/> 

    <xsl:template match="/"> 
    <xsl:call-template name="count-matches"> 
     <xsl:with-param name="set1-node" select="sets/set[1]/text[1]"/> 
     <xsl:with-param name="set2-node" select="sets/set[2]/text[1]"/> 
     <xsl:with-param name="total-count" select="0"/> 
    </xsl:call-template> 
    <xsl:text> 
</xsl:text> 
    </xsl:template> 

    <xsl:template name="count-matches"> 
    <xsl:param name="set1-node"/> 
    <xsl:param name="set2-node"/> 
    <xsl:param name="total-count" select="0"/> 
    <xsl:variable name="this-count"> 
     <xsl:choose> 
     <xsl:when test="contains($set1-node, $set2-node)"> 
      <xsl:value-of select="1"/> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="0"/> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:variable> 
    <xsl:choose> 
     <xsl:when test="$set2-node/following-sibling::text"> 
     <xsl:call-template name="count-matches"> 
      <xsl:with-param name="set1-node" 
          select="$set1-node"/> 
      <xsl:with-param name="set2-node" 
          select="$set2-node/following-sibling::text[1]"/> 
      <xsl:with-param name="total-count" 
          select="$total-count + $this-count"/> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:when test="$set1-node/following-sibling::text"> 
     <xsl:call-template name="count-matches"> 
      <xsl:with-param name="set1-node" 
          select="$set1-node/following-sibling::text[1]"/> 
      <xsl:with-param name="set2-node" 
          select="$set2-node/preceding-sibling::text[last()]"/> 
      <xsl:with-param name="total-count" 
          select="$total-count + $this-count"/> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="$total-count + $this-count"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 

</xsl:stylesheet> 

XSLT는 프로그래머가 이미 정의 된 변수에 새 값을 할당 할 수 없기 때문에 간결하지만 재귀가 필요한 경우가 많습니다. XSLT 1.0에서 Zack이 요청한 정렬 수를 얻기 위해 xsl:for-each을 사용하는 방법이 없습니다.

+0

Chuck, 일치 횟수를 찾는 간단하고 순수한 XSLT 1.0 솔루션 (확장 프로그램 필요 없음)이 있습니다. 내 대답보기 –

1

간단하고 순수한 XSLT 1이 있습니다.정확한 결과가를 제작

<t> 
    <cities> 
     <city>/Geography/North America/California/San Francisco</city> 
     <city>/Geography/Asia/Japan/Tokyo/Shinjuku</city> 
    </cities> 
    <regions> 
     <region>/Geography/North America/</region> 
     <region>/Geography/Asia/Japan/</region> 
    </regions> 
</t> 

:이 변환은 다음과 같은 XML 문서에인가

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 

    <xsl:template match="/"> 
     <xsl:variable name="vStars"> 
      <xsl:for-each select="*/regions/*"> 
       <xsl:for-each select="/*/cities/*[starts-with(.,current())]"> 
        <xsl:value-of select="'*'"/> 
       </xsl:for-each> 
      </xsl:for-each> 
     </xsl:variable> 

     <xsl:value-of select="string-length($vStars)"/> 
    </xsl:template> 
</xsl:stylesheet> 

: 일치의 카운트를 찾는 0 용액 (어떤 정보가 불필요) :

참고은 일치하는 항목마다 하나의 문자 (별표)가 생성되며이 모든 별표는 $vStars 변수의 콘텐츠를 구성합니다. 그런 다음 간단히 string-length()을 출력합니다.

관련 문제