2011-12-04 1 views
1

변수에 항목 목록을 만들고 해당 항목이 이미 목록에 있는지 확인하려고합니다. 항목은 내 질문에 중요하지 않은 입력 문서로 제공됩니다.XSLT 읽기/변경 결과 트리 생성시

그래서 제가 풀려고하는 두 가지 문제가 있습니다.

1 : 나는 현재

이 발생하고있어 변수에서 데이터를 읽을 다음은 변수

의 노드에 텍스트를 추가하는 것은 지금까지 시도한 작업은 다음과 같습니다

<xsl:variable name="data"> 
    <list> 
     <xsl:call-template name="generate"/> 
    </list> 
</xsl:variable> 


<xsl:template name="generate" match="/"> 
    <xsl:apply-templates select="//thing"/> 
</xsl:template> 


<xsl:template match="//thing"> 
    <xsl:variable name="temp"> 
     <xsl:value-of select="./text()"/> 
    </xsl:variable> 

    <xsl:choose> 
     <!-- test however this thing is already in $data --> 
     <!-- problem #1: here, trying to read anything out of $data doesn't work --> 
     <xsl:when test="contains($data/list/item/text(), $temp/text())"> 
      <xsl:for-each select="$data/list/item"> 
       <xsl:if test="contains(./text(), $temp/text())"> 
        <!-- problem #2: append any string to self::node()/text() --> 
       </xsl:if> 
      </xsl:for-each> 
     </xsl:when> 
     <xsl:otherwise> 
      <item> 
       <xsl:value-of name="$temp/text()"/> 
      </item> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

결과 트리 조각 등을 많이 검색했지만 그 방법을 알지 못했습니다.

편집 :

<data> 
<thing>string1</thing> 
<thing>string2</thing> 
<thing>string3</thing> 
<nested><thing>string1</thing></nested> 
<nested><thing>string1</thing></nested> 
<nested><thing>string2</thing></nested> 
</data> 

출력 :

<list> 
<item>string1 string1 string1</item> 
<item>string2 string2</item> 
<item>string3</item> 
</list> 

크리스

+0

사용자가 가지고있는 XML 입력 샘플과 작성할 출력을 게시하려면 XSLT 접근 방식을 제안 할 수 있습니다. 현재 문제에 대한 설명이 너무 절차 적이라고 걱정됩니다. XSLT는 선언적 언어입니다. –

+0

입력 파일이 매우 복잡하므로 샘플 코드를 작게 유지하려고 했으므로 샘플 입력을 게시하는 것이 쉽지 않습니다. 시도해 보겠습니다 ... – Chris

+0

시도하십시오. 또는 XSLT (XSLT 1.0 : http://www.jenitennison.com/xslt/grouping/muenchian.xml, XSLT 2.0 : http://www.w3.org/TR/xslt20/#grouping-examples)에서 그룹화를 읽어보십시오.), 내 현재 추측은 당신이 필요로하거나 원하는 XSLT 접근 방식이다. –

답변

5

<data> 
<thing>string1</thing> 
<thing>string2</thing> 
<thing>string3</thing> 
<nested><thing>string1</thing></nested> 
<nested><thing>string1</thing></nested> 
<nested><thing>string2</thing></nested> 
</data> 

nput이 (독립적 마틴 호넨에서) 내 대답이다, 그러나 나는 당신의 주요 질문에 대답하지 않는 것을 깨닫게 - 트리를 탐색하는 방법 처리가 이미 누적 된 데이터를 사용하는 곳에서 데이터를 처리하고 누적합니다. I이 .. 제 대답의 두 번째 부분에 용액을 원 제공이 변환이 제공된 XML 문서에인가

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="kThingByVal" match="thing" 
    use="."/> 

<xsl:template match="/"> 
    <list> 
     <xsl:apply-templates select= 
     "//thing 
      [generate-id() 
      = 
      generate-id(key('kThingByVal', .)[1]) 
      ] 
     "> 
     </xsl:apply-templates> 
    </list> 
</xsl:template> 

<xsl:template match="thing"> 
    <item> 
    <xsl:apply-templates mode="gen" 
     select="key('kThingByVal', .)"/> 
    </item> 
</xsl:template> 

<xsl:template match="thing" mode="gen"> 
    <xsl:if test="not(position() = 1)"> 
    <xsl:text> </xsl:text> 
    </xsl:if> 
    <xsl:value-of select="."/> 
</xsl:template> 
</xsl:stylesheet> 

: 원하는 정확한 결과를 제작

<data> 
    <thing>string1</thing> 
    <thing>string2</thing> 
    <thing>string3</thing> 
    <nested> 
     <thing>string1</thing> 
    </nested> 
    <nested> 
     <thing>string1</thing> 
    </nested> 
    <nested> 
     <thing>string2</thing> 
    </nested> 
</data> 

:

<list> 
    <item>string1 string1 string1</item> 
    <item>string2 string2</item> 
    <item>string3</item> 
</list> 

II. 이 문제의 일반적인 해결책은 :

FXSL의 f:foldl()과 같은 함수를 사용하여 목록을 처리하는 것과 동일한 방식으로 트리를 처리 할 수 ​​있기를 원합니다.

다음은 고전적인 응용 프로그램입니다. f:foldl() (XSLT 1의 경우.

testFoldl.xsl :

<xsl:stylesheet version="1.0" 
xmlns:f="http://fxsl.sf.net/" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:foldr-func="foldr-func" 
exclude-result-prefixes="xsl f foldr-func" 
> 

    <xsl:import href="foldl.xsl"/> 

    <!-- This transformation must be applied to: 
     numList.xml 
    --> 
    <foldr-func:foldr-func/> 
    <xsl:variable name="vFoldrFun" select="document('')/*/foldr-func:*[1]"/> 
    <xsl:output encoding="UTF-8" omit-xml-declaration="yes"/> 

    <xsl:template match="/"> 

     <xsl:call-template name="foldl"> 
     <xsl:with-param name="pFunc" select="$vFoldrFun"/> 
     <xsl:with-param name="pList" select="/*/*"/> 
     <xsl:with-param name="pA0" select="0"/> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template mode="f:FXSL" 
     match="foldr-func:*"> 
     <xsl:param name="arg1" select="0"/> 
     <xsl:param name="arg2" select="0"/> 

     <xsl:value-of select="$arg1 + $arg2"/> 
    </xsl:template> 

</xsl:stylesheet> 
0이 템플릿이 아닌 xsl:function) 새로운 결과를 현재의 누적 된 결과와 curent리스트 항목을 취하여 생성하는 함수 어떤 목록을 처리 할 수있다

이 변환은 (번호 목록을 나타냄)이 XML 문서 적용된다

<nums> 
    <num>01</num> 
    <num>02</num> 
    <num>03</num> 
    <num>04</num> 
    <num>05</num> 
    <num>06</num> 
    <num>07</num> 
    <num>08</num> 
    <num>09</num> 
    <num>10</num> 
</nums> 

원하는 결과 (모든리스트 항목의 합) 생성됩니다

55 

것은 우리가 매개 변수로하지 add() 기능을하지만, mult() 기능을 통과 (그리고 경우 목록에서 0를 제거하는 것이, 메모를 수행 새로운 "0"파라미터 - 1 - 곱하기의 중립수를 지정하면 모든 목록 항목의 곱을 얻을 수 있습니다 - 10! (10 계승).

따라서 f:foldl()은 누적 결과 및 현재 목록 항목을 기반으로 새 결과가 생성되는 모든 목록을 처리하는 데 사용할 수있는 매우 강력한 기능입니다.

이 주제가 흥미로워 보인다면, 더 흥미로운 것들이 많이 있습니다. here.

접이식 tree2.xsl : 흥미롭게

는 트리 처리 유사한 기능이 존재 트리 외에, 여기

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:f="http://fxsl.sf.net/" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
xmlns:ext="http://exslt.org/common" 
exclude-result-prefixes="f ext msxsl xsl" 
> 
<xsl:template name="foldl-tree2"> 
    <xsl:param name="pFuncNode" select="/.."/> 
    <xsl:param name="pFuncSubtrees" select="/.."/> 
    <xsl:param name="pA0"/> 
    <xsl:param name="pNode" select="/.."/> 

    <xsl:choose> 
    <xsl:when test="not($pNode)"> 
      <xsl:copy-of select="$pA0"/> 
    </xsl:when> 

    <xsl:otherwise> 
    <xsl:variable name="vSubtrees" select="$pNode/*"/> 

    <xsl:variable name="vSubTreeResult"> 
     <xsl:call-template name="foldl-tree_"> 
     <xsl:with-param name="pFuncNode" select="$pFuncNode"/> 
     <xsl:with-param name="pFuncSubtrees" select="$pFuncSubtrees"/> 
     <xsl:with-param name="pA0" select="$pA0"/> 
     <xsl:with-param name="pSubTrees" select="$vSubtrees"/> 
     </xsl:call-template> 
    </xsl:variable> 

    <xsl:apply-templates select="$pFuncNode[1]" mode="f:FXSL"> 
    <xsl:with-param name="arg0" select="$pFuncNode[position() > 1]"/> 
    <xsl:with-param name="arg1" select="$pNode"/> 
    <xsl:with-param name="arg2" select="ext:node-set($vSubTreeResult)"/> 
    </xsl:apply-templates> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template name="foldl-tree_"> 
    <xsl:param name="pFuncNode" select="/.."/> 
    <xsl:param name="pFuncSubtrees" select="/.."/> 
    <xsl:param name="pA0"/> 
    <xsl:param name="pSubTrees" select="/.."/> 

    <xsl:choose> 
    <xsl:when test="not($pSubTrees)"> 
      <xsl:copy-of select="$pA0"/> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:variable name="vSubTree1Result"> 
     <xsl:call-template name="foldl-tree2"> 
      <xsl:with-param name="pFuncNode" select="$pFuncNode"/> 
      <xsl:with-param name="pFuncSubtrees" select="$pFuncSubtrees"/> 
      <xsl:with-param name="pA0" select="$pA0"/> 
      <xsl:with-param name="pNode" select="$pSubTrees[1]"/> 
     </xsl:call-template> 
     </xsl:variable> 

     <xsl:variable name="vRestSubtreesResult"> 
     <xsl:call-template name="foldl-tree_"> 
      <xsl:with-param name="pFuncNode" select="$pFuncNode"/> 
      <xsl:with-param name="pFuncSubtrees" select="$pFuncSubtrees"/> 
      <xsl:with-param name="pA0" select="$pA0"/> 
      <xsl:with-param name="pSubTrees" select="$pSubTrees[position() > 1]"/> 
     </xsl:call-template> 
     </xsl:variable> 

    <xsl:apply-templates select="$pFuncSubtrees" mode="f:FXSL"> 
     <xsl:with-param name="arg0" select="$pFuncSubtrees[position() > 1]"/> 
     <xsl:with-param name="arg1" select="ext:node-set($vSubTree1Result)"/> 
     <xsl:with-param name="arg2" select="ext:node-set($vRestSubtreesResult)"/> 
    </xsl:apply-templates> 
    </xsl:otherwise> 
    </xsl:choose>  
</xsl:template> 
</xsl:stylesheet> 

을 제로 (초기 결과) 및 (누적 된 결과와 함께) 각 트리 노드를 처리하는 함수는 트리 노드의 모든 하위 트리 집합과 누적 된 결과를 지금까지 사용한 함수를 매개 변수로 전달하여 새로운 결과를 생성합니다. 또한 트리의 최상위 노드를 매개 변수로 전달해야합니다.

시험 foldlTree2 : 여기

foldl-tree2()를 사용하는 간단한 예시이다.XSL는 :

55 
:

<nums> 
    <a> 
    <b> 
    <num>01</num> 
    </b> 
    </a> 
    <c> 
    <num>02</num> 
    <num>03</num> 
    <num>04</num> 
    <d> 
    <num>05</num> 
    <num>06</num> 
    </d> 
    </c> 
    <num>07</num> 
    <num>08</num> 
    <num>09</num> 
    <num>10</num> 
</nums> 

가 모두 같은 숫자의 합을 생성합니다

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:add-tree="add-tree" 
xmlns:f="http://fxsl.sf.net/" 
exclude-result-prefixes="xsl f add-tree" 
> 
    <xsl:import href="foldl-tree2.xsl"/> 

    <xsl:strip-space elements="*"/> 
    <add-tree:add-tree/> 

    <xsl:output method="text"/> 

    <xsl:template match="/"> 
     <xsl:variable name="vAdd" select="document('')/*/add-tree:*[1]"/> 

     <xsl:call-template name="foldl-tree2"> 
     <xsl:with-param name="pFuncNode" select="$vAdd"/> 
     <xsl:with-param name="pFuncSubtrees" select="$vAdd"/> 
     <xsl:with-param name="pA0" select="0"/> 
     <xsl:with-param name="pNode" select="/*"/> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template match="add-tree:*" mode="f:FXSL"> 
     <xsl:param name="arg1"/> 
     <xsl:param name="arg2"/> 

     <xsl:variable name="varg1"> 
     <xsl:call-template name="nodeValue"> 
     <xsl:with-param name="pNode" select="$arg1"/> 
     </xsl:call-template> 
     </xsl:variable> 

     <xsl:variable name="varg2"> 
     <xsl:call-template name="accumValue"> 
     <xsl:with-param name="pAccum" select="$arg2"/> 
     </xsl:call-template> 
     </xsl:variable> 

     <xsl:value-of select="$varg1 + $varg2"/> 
    </xsl:template> 

    <xsl:template name="nodeValue"> 
    <xsl:param name="pNode"/> 
    <xsl:call-template name="toNumber"> 
     <xsl:with-param name="pX" select="$pNode/text()[1]"/> 
    </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="accumValue"> 
    <xsl:param name="pAccum"/> 
    <xsl:call-template name="toNumber"> 
     <xsl:with-param name="pX" select="$pAccum"/> 
    </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="toNumber"> 
    <xsl:param name="pX"/> 

    <xsl:choose> 
     <xsl:when test="not(number($pX) = number($pX))">0</xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="number($pX)"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

이러한 변화는 어떤 누구의 텍스트 노드 숫자를을 포함하는 모든 나무에 적용하는 경우

지금은에 다른 매개 변수를 전달하기 만하면됩니다. 원래의 문제에서 요구 6,754,073,210 있으며, 별도 item 하에서 모두 동일한 값으로 모든 thing 요소 값의 occurencies 목록을 추출한다 :이 변환은 원래 제공된 XML에인가

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
xmlns:ext="http://exslt.org/common" 
xmlns:merge-list="merge-list" 
xmlns:f="http://fxsl.sf.net/" 
exclude-result-prefixes="xsl f ext msxsl merge-list" 
> 
    <xsl:import href="foldl-tree2.xsl"/> 

    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <merge-list:merge-list/> 

    <xsl:variable name="vrtfZero"> 
    <list/> 
    </xsl:variable> 

    <xsl:variable name="vZero" select= 
    "document('')/*/xsl:variable[@name='vrtfZero']/* 
    "/> 

    <xsl:template match="/"> 
     <xsl:variable name="vFunMerge" select="document('')/*/merge-list:*[1]"/> 

     <list> 
     <xsl:call-template name="foldl-tree2"> 
     <xsl:with-param name="pFuncNode" select="$vFunMerge"/> 
     <xsl:with-param name="pFuncSubtrees" select="$vFunMerge"/> 
     <xsl:with-param name="pA0" select="$vZero"/> 
     <xsl:with-param name="pNode" select="/*"/> 
     </xsl:call-template> 
     </list> 
    </xsl:template> 

    <xsl:template match="merge-list:*" mode="f:FXSL"> 
     <xsl:param name="arg1"/> 
     <xsl:param name="arg2"/> 

     <xsl:variable name="vrtfArg1"> 
     <xsl:apply-templates mode="gen" select="$arg1"/> 
     </xsl:variable> 

     <xsl:variable name="vrtfArg2"> 
     <xsl:apply-templates mode="gen" select="$arg2"/> 
     </xsl:variable> 

     <xsl:variable name="vArg1" select="ext:node-set($vrtfArg1)/*"/> 
     <xsl:variable name="vArg2" select="ext:node-set($vrtfArg2)/*"/> 

     <xsl:for-each select="$vArg1[self::thing or self::item]"> 
     <xsl:variable name="vMatch" select= 
     "$vArg2[self::thing or self::item 
       and 
       substring-before(concat(., ' '), ' ') 
       = 
       substring-before(concat(current(), ' '), ' ') 
       ]"/> 
     <xsl:choose> 
      <xsl:when test="$vMatch"> 
      <item> 
      <xsl:value-of select="$vMatch/text()"/> 
      <xsl:text> </xsl:text> 
      <xsl:value-of select="."/> 
      </item> 
      </xsl:when> 
      <xsl:otherwise> 
      <xsl:copy-of select="."/> 
      </xsl:otherwise> 
     </xsl:choose> 
     </xsl:for-each> 

     <xsl:for-each select="$vArg2[self::thing or self::item]"> 
     <xsl:variable name="vMatch" select= 
     "$vArg1[self::thing or self::item 
       and 
       substring-before(concat(., ' '), ' ') 
       = 
       substring-before(concat(current(), ' '), ' ') 
       ]"/> 
      <xsl:if test="not($vMatch)"> 
      <xsl:copy-of select="."/> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template match="thing" mode="gen"> 
    <item><xsl:value-of select="."/></item> 
    </xsl:template> 

    <xsl:template match="item" mode="gen"> 
    <xsl:copy-of select="."/> 
    </xsl:template> 

    <xsl:template match="*" mode="gen"/> 

    <xsl:template mode="gen" match="/"> 
    <xsl:apply-templates select="*" mode="gen"/> 
    </xsl:template> 
</xsl:stylesheet> 

문서 : 원하는 정확한 결과가을 생산

<data> 
    <thing>string1</thing> 
    <thing>string2</thing> 
    <thing>string3</thing> 
    <nested> 
     <thing>string1</thing> 
    </nested> 
    <nested> 
     <thing>string1</thing> 
    </nested> 
    <nested> 
     <thing>string2</thing> 
    </nested> 
</data> 

:

<list> 
    <item>string1 string1 string1</item> 
    <item>string2 string2</item> 
    <item>string3</item> 
</list> 
+0

"트리를 가로 지르는 방법과 처리 과정에서 이미 누적 된 데이터가 사용되는 곳에서 데이터를 축적하는 방법"이것은 정확히 내가 시도한 것입니다. 귀하의 회신을 기다리고 있습니다. – Chris

+0

@Chris : 오늘 아침 일찍 심부름을했습니다. 지금이 일하고있어. :) –

+0

@Chris : 완료. :) –

2

스타일 시트

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

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

    <xsl:key name="k1" match="thing" use="."/> 

    <xsl:template match="data"> 
    <list> 
     <xsl:apply-templates select="descendant::thing[generate-id() = generate-id(key('k1', .)[1])]" mode="group"/> 
    </list> 
    </xsl:template> 

    <xsl:template match="thing" mode="group"> 
    <item> 
     <xsl:apply-templates select="key('k1', .)"/> 
    </item> 
    </xsl:template> 

    <xsl:template match="thing"> 
    <xsl:if test="position() &gt; 1"> 
     <xsl:text> </xsl:text> 
    </xsl:if> 
    <xsl:value-of select="."/> 
    </xsl:template> 

</xsl:stylesheet> 

는 I 변환 이 입력 코드이어야 출력

<list> 
    <item>string1 string1 string1</item> 
    <item>string2 string2</item> 
    <item>string3</item> 
</list> 
+0

도움을 주셔서 감사합니다. 내 응용 프로그램에서 이와 같은 그룹화 기능을 사용할 수 있는지 확인합니다. – Chris