2011-02-02 4 views
1

저는 xslt를 처음 사용합니다.이 문제는 절차 적 사고 방식에 신경을 쓰고 있습니다.xslt의 필드를 병합하고 이름을 바꿉니다.

나는 이름을 바꾸려는 경우가 있고, 경우에 따라 축약하고 싶은 정보가 있습니다. 이름 바꾸기는 처리 할 수 ​​있지만 응축이 나를 걸고 있습니다. 나의 접근 방식은 모든것의 이름을 바꾸는 것이었고, 이름 바꾸기에서 중복이 생기면 중복을 제거하는 것이었다. 명확성을 위해 몇 가지 코드가 있습니다.

입력 :

<variables> 
    <var value="a-value"> a </var> 
    <var value="b-value"> b </var> 
    <var value="c-value"> c </var> 
    <var value="d-value"> d </var> 
</variables> 

원하는 출력 :

<variables> 
    <var value="new-a-value"> new-a </var> 
    <var value="new-b-and-c-value"> new-b-and-c </var> 
    <var value="new-d-value"> new-d </var> 
</variables> 

내 XSLT :

<xsl:for-each select="var"> 
    <xsl:choose> 

     <xsl:when test="@value = 'a-value'"> 
     <var value="new-a-value"> new-a </var> 
     </xsl:when> 

     <xsl:when test="@value = 'b-value'"> 
     <var value="new-b-and-c-value"> new-b-and-c </var> 
     </xsl:when> 

     <xsl:when test="@value = 'c-value'"> 
     <var value="new-b-and-c-value"> new-b-and-c </var> 
     </xsl:when> 

     <xsl:when test="@value = 'd-value'"> 
     <var value="new-d-value"> new-d </var> 
     </xsl:when> 

    </xsl:choose> 
    </xsl:for-each> 
나는 이름 변경 후 중복 용어를 제거 할. 나는 여기서 어디로 가야할지 모르겠다. 내 직감은 b 값 또는 c 값이 발견되거나 중복을 제거하는 중간 처리 된 xml을 통해 다른 반복을 실행할 때 어떤 종류의 체크를 설정하려고하지만 둘 중 한 방법이 xslt에서 실행 가능.

답변

1

"중복을 제거하는 중간 처리 된 XML을 통해 다른 반복 실행"관련 - XSLT 2.0 또는 XSLT 1.0에 노드 집합 확장이있는 경우 가능합니다. 그러나 나는이 경우에 그것이 필요하다고 생각하지 않는다.

A를위한 - 각과 선택 - 때 - 테스트, 그렇지 않습니다보다는 적용 템플릿 :

<xsl:apply-templates select="var" /> 

은 그럼 당신은 약에 해당하는, 당신이 처리 할 VAR의 각 유형에 대한 템플릿을 가지고 당신의 XSL : 요소 :

<xsl:template match="var[@value = 'a-value']"> 
    <var value="new-a-value"> new-a </var> 
</xsl:template> 

그리고 B/C 항목, 같은 :

<xsl:template match="var[@value = 'b-value' or @value = 'c-value'][1]"> 
    <var value="new-b-and-c-value"> new-b-and-c </var> 
</xsl:template> 

은 형제 중 첫 번째와 같은 var에 대해서만 템플릿을 실행합니다. 이것이 정확히 원하는 것인지 여부는 입력 구조가 어떻게 달라질 수 있는지에 달려 있습니다. 그러나 샘플 입력이 있으면 작동합니다. 또한 첫 번째가 아닌 b 또는 c 변수를 처리하는 템플릿이 필요합니다.

<xsl:template match="var[@value = 'b-value' or @value = 'c-value']" 
     priority="-1" /> 

빈 몸체에주의하십시오. 우선 순위가 낮아서 인 b/c 값이 먼저이 템플릿에 의해 처리되지 않습니다.즉 어떻게 든, 당신이 생각했던 것과 일치 알려 우리는 반복 할 수없는 경우

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/variables"> 
     <xsl:copy> 
     <xsl:apply-templates select="var"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="var[@value = 'a-value']"> 
     <var value="new-a-value"> new-a </var> 
    </xsl:template> 

    <xsl:template match="var[@value = 'b-value' or @value = 'c-value'][1]"> 
     <var value="new-b-and-c-value"> new-b-and-c </var> 
    </xsl:template> 

    <xsl:template match="var[@value = 'b-value' or @value = 'c-value']" 
     priority="-1" /> 

    <xsl:template match="var[@value = 'd-value']"> 
     <var value="new-d-value"> new-d </var> 
    </xsl:template> 
</xsl:stylesheet> 

: 샘플 입력 주어 합산

은 다음 XSLT 스타일 시트는 요청 된 출력을 제공합니다.

입력에 'b'가 하나만 있다는 것을 알고 있으면 더 간단 해지고 'b'와 일치하는 템플릿을 가지고 새 값으로 대체 할 수 있습니다. 'c'와 일치시키고 버리는 빈 템플릿이 있습니다. 더 간단 진짜 문제를 만들기 명확 가져옵니다 : 매핑 된 키 값을 그룹화하지만

+0

+1 좋은 대답. 나는 부정적인 것보다는 더 높은 우선 순위를 줄 것이다. –

+0

@Alej :'[1]'템플릿에 더 높은 우선 순위를 부여하겠습니까? 빈 템플릿보다 우선 순위가 낮습니다. 처음에는 같은 템플릿에서 더 높은 우선 순위로 변경할 것을 의미한다고 생각했습니다. – LarsH

+0

+1 좋은 접근 방식. – Flack

3

리팩토링 ... 어쩌면 당신이 가정을 만들 수 없습니다 같은 소리가났다.

이 스타일 :

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:v="value" 
exclude-result-prefixes="v"> 
    <xsl:key name="kVarByReplace" 
      match="var" 
      use="document('')/*/v:v[@o=current()/@value]/@n"/> 
    <v:v o="a-value" n="new-a-value"/> 
    <v:v o="b-value" n="new-b-and-c-value"/> 
    <v:v o="c-value" n="new-b-and-c-value"/> 
    <v:v o="d-value" n="new-d-value"/> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="var"> 
     <xsl:variable name="vKey" 
         select="document('')/*/v:v[@o=current()/@value]/@n"/> 
     <xsl:if test="count(.|key('kVarByReplace',$vKey)[1]) = 1"> 
      <var value="{$vKey}"> 
       <xsl:value-of select="$vKey"/> 
      </var> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

출력 :

<variables> 
    <var value="new-a-value">new-a-value</var> 
    <var value="new-b-and-c-value">new-b-and-c-value</var> 
    <var value="new-d-value">new-d-value</var> 
</variables> 

: xsl:key/@use에서 document() 기능의 사용.

이것은이 XSLT 2.0 것이 얼마나 쉬운 지 보여줍니다지도에 대한 또한 키

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:variable name="vMap" as="element()*"> 
     <v o="a-value">new-a-value</v> 
     <v o="b-value">new-b-and-c-value</v> 
     <v o="c-value">new-b-and-c-value</v> 
     <v o="d-value">new-d-value</v> 
    </xsl:variable> 
    <xsl:template match="variables"> 
     <variables> 
      <xsl:for-each-group select="var" 
           group-by="$vMap[@o=current()/@value]"> 
       <var value="{current-grouping-key()}"> 
        <xsl:value-of select="current-grouping-key()"/> 
       </var> 
      </xsl:for-each-group> 
     </variables> 
    </xsl:template> 
</xsl:stylesheet> 

첫 번째 솔루션을.

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:v="value" 
exclude-result-prefixes="v"> 
    <xsl:key name="kValByOld" match="v:v" use="@o"/> 
    <xsl:key name="kVarByReplace" 
      match="var" 
      use="document('')/*/v:v[@o=current()/@value]/@n"/> 
    <xsl:variable name="vStylesheet" select="document('')"/> 
    <v:v o="a-value" n="new-a-value"/> 
    <v:v o="b-value" n="new-b-and-c-value"/> 
    <v:v o="c-value" n="new-b-and-c-value"/> 
    <v:v o="d-value" n="new-d-value"/> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="var"> 
     <xsl:variable name="vOld" select="@value"/> 
     <xsl:for-each select="$vStylesheet"> 
      <xsl:variable name="vNew" 
          select="key('kValByOld',$vOld)/@n"/> 
      <xsl:for-each select="$vOld"> 
       <xsl:if test="count(..|key('kVarByReplace',$vNew)[1])=1"> 
        <var value="{$vNew}"> 
         <xsl:value-of select="$vNew"/> 
        </var> 
       </xsl:if> 
      </xsl:for-each> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 
+0

+1 흥미로운 솔루션입니다. – Flack

2

다음은 입력에서 원하는 출력을 생성하는 XSLT 2.0 스타일 시트입니다. 그것은 다른 입력과 올바른 일을 여부는 또 다른 문제이지만, 적절히 확장 가능하고 이런 종류의 문제에 사용할 수있는 다양한 기술을 보여주기 위해 설계 :

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:f="http://local-functions/" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
exclude-result-prefixes="f xs"> 

<xsl:output indent="yes"/> 

<xsl:template match="variables"> 
    <variable> 
    <xsl:for-each-group select="*" group-adjacent="f:is-groupable(.)"> 
     <xsl:choose> 
      <xsl:when test="f:is-groupable(.)"> 
       <var value="new-{string-join(current-group()/replace(@value, '-value', ''), '-and-')}-value"> 
       <xsl:text> new-</xsl:text> 
       <xsl:value-of select="string-join(current-group()/normalize-space(.), '-and-')"/> 
       <xsl:text> </xsl:text> 
       </var> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:for-each select="current-group()"> 
       <var value="new-{@value}"> 
        <xsl:value-of select="replace(., '\S+', 'new-$0')"/> 
       </var> 
       </xsl:for-each>  
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:for-each-group> 
    </variable> 
</xsl:template> 

<xsl:function name="f:is-groupable" as="xs:boolean"> 
    <xsl:param name="var" as="element(var)"/> 
    <xsl:sequence select="$var/@value = ('b-value', 'c-value')"/> 
</xsl:function>  

</xsl:stylesheet>