2017-03-29 6 views
0

거대한 XML (약 300MB)을 반복 된 하위 요소를 기반으로 작은 파일로 분할하려고합니다. 아래XSLT가 하나의 xml을 여러 xml로 분할하여 부모 요소 유지

예 시나리오를

input.xml을 설명이 전술 한 바와 같이

<?xml version="1.0" encoding="UTF-8"?> 
<a> 
    <b></b> 
    <bb></bb> 
    <bbb> 
     <c> 
      <d id="1"> 
       <x></x> 
       <y></y> 
      </d> 
      <d id="2"> 
       <x></x> 
       <y></y> 
      </d> 
      <d id="3"> 
       <x></x> 
       <y></y> 
      </d> 
     </c> 
    </bbb> 
    <e></e> 
    <f></f> 
</a> 

반복 하위 요소를 갖는다. 이 요소를 기반으로 별도의 출력 파일은 상위 요소 및 속성을 그대로 유지함으로써 예상됩니다.

예상 출력 out_1_a.xml

<?xml version="1.0" encoding="UTF-8"?> 
<a> 
    <b></b> 
    <bb></bb> 
    <bbb> 
     <c> 
      <d id="1"> 
       <x></x> 
       <y></y> 
      </d> 
     </c> 
    </bbb> 
    <e></e> 
    <f></f> 
</a> 

예상 출력 out_2_a.xml

<?xml version="1.0" encoding="UTF-8"?> 
<a> 
    <b></b> 
    <bb></bb> 
    <bbb> 
     <c> 
      <d id="2"> 
       <x></x> 
       <y></y> 
      </d> 
     </c> 
    </bbb> 
    <e></e> 
    <f></f> 
</a> 

예상 출력 out_3_a.xml

<?xml version="1.0" encoding="UTF-8"?> 
<a> 
    <b></b> 
    <bb></bb> 
    <bbb> 
     <c> 
      <d id="3"> 
       <x></x> 
       <y></y> 
      </d> 
     </c> 
    </bbb> 
    <e></e> 
    <f></f> 
</a> 

내 XSL - sample.xsl

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

<xsl:output indent="yes"/> 

<xsl:template match="/"> 
    <xsl:for-each select="a/bbb/c/d"> 
    <xsl:variable name="i" select="position()" /> 
    <xsl:result-document method="xml" href="out_{$i}_a.xml"> 
    <a> 
     <b></b> 
     <bb></bb> 
     <bbb> 
      <c> 
       <xsl:copy-of select="../@* | ." /> 
      </c> 
     </bbb> 
     <e></e> 
     <f></f> 
    </a> 
    </xsl:result-document> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

이 작품을 좋아하고 내가 원하는 출력을 얻을. 그러나 a, b, bb 등과 같은 부모 요소를 하드 코딩하는 것보다 더 좋은 방법이 있다고 확신합니다. 또한 경우에 따라 이러한 부모 요소에 특성이 포함되어 있으며 동적 요소가 있습니다. 그래서 하드 코딩은 내가 피하고 싶은 것입니다. 이 문제를 해결하는 더 좋은 방법은 무엇입니까?

답변

2

이를 사용할 수 있습니다

<xsl:template match="d"> 
    <xsl:variable name="name" select="generate-id()"/> 
    <xsl:variable name="outputposition"><xsl:value-of select="count(preceding::d)+1"></xsl:value-of></xsl:variable> 
    <xsl:result-document method="xml" href="out_{$outputposition}_a.xml" indent="yes"> 
     <xsl:call-template name="spilit"> 
      <xsl:with-param name="name" select="$name"/> 
      <xsl:with-param name="element" select="root()"/> 
     </xsl:call-template> 
    </xsl:result-document> 
</xsl:template> 

<xsl:template name="spilit"> 
    <xsl:param name="name"/> 
    <xsl:param name="element"/> 
    <xsl:for-each select="$element[descendant-or-self::d[generate-id() eq $name]]"> 
     <xsl:choose> 
      <xsl:when test="self::d[generate-id() = $name]"> 
       <xsl:copy> 
        <xsl:copy-of select="@*"></xsl:copy-of> 
        <xsl:copy-of select="node()"></xsl:copy-of> 
       </xsl:copy> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:copy-of select="preceding-sibling::*"/> 
       <xsl:copy> 
        <xsl:call-template name="spilit"> 
         <xsl:with-param name="name" select="$name"/> 
         <xsl:with-param name="element" select="child::*[descendant-or-self::d[generate-id() eq $name]]"/> 
        </xsl:call-template> 
       </xsl:copy> 
       <xsl:copy-of select="following-sibling::*"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:for-each> 
</xsl:template> 
+1

생성되는 출력 파일의 구조가 OP와는 다른 구조입니다. '선제 형제 자매'와'추종 형제 자매'의 복사는 적절한 장소에 있지 않습니다. –

+0

고마워요 @ LingamurthyCS, 이제 스크립트를 업데이트했습니다 – Rupesh

+0

안녕 루페 쉬, 이건 내 시나리오에 완벽하게 작동합니다. 감사. 그러나 요소 d의 id 특성과 일치하는 것과 관련하여 한 가지 질문이 있습니다. 요소 d에 atttributes가 없으면 분할하는 방법이 있습니까? –

1

XSLT - 2.0 솔루션보다 쉽게 ​​작업을 수행해야합니다

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

    <xsl:template match="@* | node()" mode="createDoc"> 
     <xsl:param name="id"/> 
     <xsl:copy> 
      <!-- apply-templates to the attributes and, the desired 'd' child element or all children elements --> 
      <xsl:apply-templates select="@*, if(node()[generate-id() = $id]) then node()[generate-id() = $id] else node()" mode="createDoc"> 
       <xsl:with-param name="id" select="$id"/> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <!-- template to create documents per `d` element --> 
    <xsl:template match="/"> 
     <xsl:for-each select="a/bbb/c/d"> 
      <xsl:result-document href="out_{@id}_a.xml"> 
       <xsl:apply-templates select="root(.)" mode="createDoc"> 
        <!-- pass the id of the desired element to be copied omitting its siblings--> 
        <xsl:with-param name="id" select="generate-id()"/> 
       </xsl:apply-templates> 
      </xsl:result-document> 
     </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet> 

두 번째 템플릿은 generate-id()를 전달하여 d 요소마다 문서를 생성 일치하는 요소를 재귀 적 템플릿 (첫 번째 템플릿)에 추가합니다.

첫 번째 템플릿은 모든 요소를 ​​반복적으로 복사합니다. 또한 을 사용하여 원하는 d 요소 만 generate-id()으로 복사하고 다른 형제는 생략합니다.