2011-10-18 3 views
1

XSLT를 사용하여 컨텐트 관리 시스템의 복잡한 XML 출력을 XHTML로 변환하고 있습니다. 나는 <xsl:apply-templates/>을 사용하여 XML 입력에 의해 기술 된 것의 XHTML 조각을 얻습니다. 이 XML 입력은 여러 가지 XSLT 템플릿 요소로 처리 할 수있는 많은 사례를 설명하는 매우 복잡한 구조로되어 있습니다. 그리고 그 구조는 장래에 상당히 자주 바뀔 수 있습니다.XSLT 노드 집합 B를 노드 집합 A의 텍스트 노드 안의 탐지 된 위치에있는 다른 노드 집합 A에 삽입하십시오.

이전에는 변형 된 결과 조각이 XSLT 출력으로 직접 전송되었습니다. 이제 요구 사항이 바뀌었고 결과를 캡처 할 필요가 있습니다. 가끔 조각의 가치가있는 특정 위치에 다른 잘 구성된 XHTML 조각을 삽입하도록 수정해야합니다.

<xsl:apply-templates/>은 변수 컨테이너에 캡처 된 일부 불투명 XHTML 조각을 생성했다고 가정합니다.

<xsl:variable name="snippet"> 
    <xsl:call-template name="get-snippet" /> 
</xsl:variable> 

요구가 $으로의 단부에있는 임의로 함유 기간 내에 삽입 될을 니펫 노드 집합하도록 말한다

<xsl:variable name="container"> 
    <xsl:apply-templates /> 
</xsl:variable> 

다음 변수 니펫에서 제 XHTML 단편 존재 $ container 값입니다. 두 변수의 XHTML 조각을 조각으로 유지하지 않으면 문제가되지 않습니다. 따라서 어느 변수의 문자열 값에서도 작동 할 수 없습니다.

<xsl:apply-templates/>의 강력 함과 유연성을 잃지 않고 XSLT에서 해당 요구 사항을 충족 할 수있는 기회가 있습니까? $에 XHTML 조각을 가져 오는 중입니까?

은 BTW : 나는 이미 사용 $container의 마지막 텍스트 노드를 액세스에 대해 알고 :

node-set($container)//child::text[last()] 

을하지만 난 그 텍스트 노드의 중간에 삽입 뭔가를 얻을 수 놓친 나는 XSLT가에 대한 적절한 지원을 제공하기 위해 실패 고려 내가 뭘하고 싶은지.

답변

2

I. XSLT 1.0 용액는 :

이 변환은 (임의의 XML 문서에 - 사용하지 않음)인가
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ext="http://exslt.org/common" 
exclude-result-prefixes="ext"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:variable name="vrtfContainer"> 
    <html> 
    <p>Hello, world.</p> 
    <p> This is <b>just</b> a <i>demo.</i></p> 
    <p> Of some text</p> 
    </html> 
</xsl:variable> 

<xsl:variable name="vContainer" select= 
    "ext:node-set($vrtfContainer)/*"/> 

<xsl:variable name="vrtfSnippet"> 
    <p>Snippet</p> 
</xsl:variable> 

<xsl:variable name="vSnippet" select= 
    "ext:node-set($vrtfSnippet)/*"/> 

    <xsl:variable name="vText" select= 
    "($vContainer//text()[contains(.,'.')])[last()]"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="/"> 
    <xsl:apply-templates select="$vContainer"/> 
</xsl:template> 

<xsl:template match="text()"> 
    <xsl:choose> 
    <xsl:when test="not(generate-id() = generate-id($vText))"> 
    <xsl:value-of select="."/> 
    </xsl:when> 
    <xsl:otherwise> 
    <xsl:call-template name="insertSnippet"> 
     <xsl:with-param name="pText" select="$vText"/> 
    </xsl:call-template> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template name="insertSnippet"> 
    <xsl:param name="pText"/> 

    <xsl:copy-of select="substring-before($pText, '.')"/> 

    <xsl:variable name="vTail" select= 
     "substring-after($pText, '.')"/> 

    <xsl:choose> 
    <xsl:when test="not(contains(substring($vTail,2), '.'))"> 
    <xsl:copy-of select="$vSnippet"/> 
    <xsl:value-of select="concat('.', $vTail)"/> 
    </xsl:when> 
    <xsl:otherwise> 
    <xsl:text>.</xsl:text> 
    <xsl:call-template name="insertSnippet"> 
    <xsl:with-param name="pText" 
     select="substring-after($pText, '.')"/> 
    </xsl:call-template> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
</xsl:stylesheet> 

, 원하는 정확한 결과 제조된다 :

<html> 
    <p>Hello, world.</p> 
    <p> This is <b>just</b> a <i>demo 
     <p>Snippet</p>.</i></p> 
    <p> Of some text</p> 
</html> 

설명 : 문자열에있는 마지막 '.'을 찾기 위해 재귀 명명 된 템플릿으로 ID 규칙을 재정의했습니다.

II. XSLT 2.0 솔루션 :

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

<xsl:variable name="vContainer"> 
    <html> 
    <p>Hello, world.</p> 
    <p> This is <b>just</b> a <i>demo.</i></p> 
    <p> Of some text</p> 
    </html> 
</xsl:variable> 


<xsl:variable name="vSnippet"> 
    <p>Snippet</p> 
</xsl:variable> 

    <xsl:variable name="vText" select= 
    "($vContainer//text()[contains(.,'.')])[last()]"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="/"> 
    <xsl:apply-templates select="$vContainer/*"/> 
</xsl:template> 

<xsl:template match="text()[. is $vText]"> 
    <xsl:variable name="vInd" select= 
    "index-of(string-to-codepoints(.), string-to-codepoints('.'))[last()]"/> 
    <xsl:sequence select="substring(., 1, $vInd -1)"/> 
    <xsl:sequence select="$vSnippet/*"/> 
    <xsl:sequence select="substring(., $vInd)"></xsl:sequence> 
</xsl:template> 
</xsl:stylesheet> 

때이 XSLT 2.0 변환 다시 원하는 정확한 결과를 생성한다 행한다 :

<html> 
    <p>Hello, world.</p> 
    <p> This is <b>just</b> a <i>demo 
     <p>Snippet</p>.</i></p> 
    <p> Of some text</p> 
</html> 

설명 : 2.0 표준의 XPath 기능 string-to-codepoints(), index-of(), substring() 오퍼레이터 is 사용.