2012-08-05 3 views
4

XML 노드를 구분 기호로 구분하고 개별 노드를 만드는 XSLT 1.0이 필요합니다. 는 예를 들어, 분리 문자는 '_'이며, XML은 다음과 같습니다XSLT - 구분 기호로 노드 분해

<root> 
    <a_b_c>hello<a_b_c> 
    <a_b_c1>world</a_b_c1> 
</root> 

결과 XML은 다음과 같아야 같이 구분 기호를 포함하지 않는

<root> 
    <a> 
     <b> 
      <c>hello</c> 
      <c1>world</c1> 
     </b> 
    </a> 
</root> 

노드가 출력되어야한다. XSLT1.0에서 정말 필요합니다. 도움을 주셔서 감사합니다.

답변

2

이 변환 :

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

    <xsl:key name="kSameNameAdj" match="*" 
    use="concat(generate-id(..), 
       '+', 
       generate-id(preceding-sibling::*[not(name()=name(current()))][1]) 
      )"/> 

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

<xsl:template match="/"> 
    <xsl:variable name="vrtfPass1"> 
    <xsl:apply-templates select="node()"/> 
    </xsl:variable> 

    <xsl:apply-templates select="ext:node-set($vrtfPass1)" mode="compress"/> 
</xsl:template> 

<xsl:template name="explode" match= 
    "*[contains(name(),'_') 
    and not(substring(name(),1,1)='_') 
    and not(substring(name(), string-length(name()))='_') 
    ]"> 
    <xsl:param name="pName" select="name()"/> 
    <xsl:param name="pText" select="text()"/> 

    <xsl:choose> 
    <xsl:when test="not($pName)"> 
    <xsl:value-of select="$pText"/> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:element name="{substring-before(concat($pName, '_'), '_')}"> 
     <xsl:call-template name="explode"> 
     <xsl:with-param name="pName" select="substring-after($pName, '_')"/> 
     <xsl:with-param name="pText" select="$pText"/> 
     </xsl:call-template> 
     </xsl:element> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

    <xsl:template match="/" name="fold" mode="compress"> 
    <xsl:param name="pDoc" select="/"/> 

    <xsl:choose> 
    <xsl:when test="not($pDoc//*[name()=name(following-sibling::*[1])])"> 
     <xsl:copy-of select="$pDoc"/> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:variable name="vrtfThisPass"> 
     <xsl:apply-templates select="$pDoc/*" mode="compress"/> 
     </xsl:variable> 

     <xsl:call-template name="fold"> 
     <xsl:with-param name="pDoc" select="ext:node-set($vrtfThisPass)"/> 
     </xsl:call-template> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template match="node()|@*" mode="compress"> 
    <xsl:copy> 
    <xsl:apply-templates select="@*|node()[1]" mode="compress"/> 
    </xsl:copy> 
    <xsl:apply-templates select="following-sibling::node()[1]" mode="compress"/> 
</xsl:template> 

<xsl:template match="*[name()=name(following-sibling::*[1])]" mode="compress"> 
    <xsl:element name="{name()}"> 
    <xsl:apply-templates mode="compress" select= 
    "key('kSameNameAdj', 
      concat(generate-id(..), 
       '+',generate-id(preceding-sibling::*) 
       ) 
     )/node()"/> 
    </xsl:element> 
    <xsl:apply-templates mode="compress" select= 
    "key('kSameNameAdj', 
      concat(generate-id(..), 
       '+',generate-id(preceding-sibling::*) 
       ) 
     ) 
      [last()]/following-sibling::node()[1] 
    "/> 
</xsl:template> 
</xsl:stylesheet> 
다음 XML 문서 적용

가 (1,를 구비 더 어려울 확장)

<root> 
    <x>This is:</x> 
    <a_b_c>hello</a_b_c> 
    <a_b_c_d>my</a_b_c_d> 
    <a_b_c1>wonderful</a_b_c1> 
    <a_b_c>world</a_b_c> 
    <a_b>!</a_b> 
    <y>The End</y> 
</root> 

는 원하는 정확한 생산 결과 :

<root> 
    <x>This is:</x> 
    <a> 
     <b> 
     <c>hello<d>my</d> 
     </c> 
     <c1>wonderful</c1> 
     <c>world</c>!</b> 
    </a> 
    <y>The End</y> 
</root> 

설명 :

.1. 이것은 다중 패스 변환입니다. 첫 번째 패스에 XML 문서를 변환 :

<root> 
    <x>This is:</x> 
    <a> 
     <b> 
     <c>hello</c> 
     </b> 
    </a> 
    <a> 
     <b> 
     <c> 
      <d>my</d> 
     </c> 
     </b> 
    </a> 
    <a> 
     <b> 
     <c1>wonderful</c1> 
     </b> 
    </a> 
    <a> 
     <b> 
     <c>world</c> 
     </b> 
    </a> 
    <a> 
     <b>!</b> 
    </a> 
    <y>The End</y> 
</root> 

.2. 필연적으로 통과하면 각 요소는 같은 이름의 인접 요소 그룹을 해당 이름이 인 단일 요소로 압축합니다. 그런 다음 동일한 이름을 가진 인접한 형제 요소가 두 개 이상있을 때까지 결과가 재귀 적으로 처리됩니다 .

.3. 첫 번째 패스는 identity rule입니다.

.4. 다음 번에 fine-grade identity 템플릿을 "압축"모드로 사용합니다.

관련 문제