Large XML file - wrapping elements inside tags using XSLT or manipulating XML as a String?

I have a fairly large XML file about 3-4 MB in size, and I need to wrap some elements inside the tags. My Xml has the following structure:

<body>
    <p></p>
    <p>
        <sectPr></sectPr>
    </p>
    <p></p>
    <p></p>
    <tbl></tbl>
    <p>
        <sectPr></sectPr>
    </p>
</body>

Of course, all items pand tblwill be repeated in bodybefore the end of the file (and each of the above elements have children - I just took them for my sake of simplicity). As an estimate, I will have about 70 elements sectPrinside body, not necessarily in the order described above.

What I would like to do is wrap all the elements that begin with the element containing sectPr, in the next element containing sectPr, in another tag. As a result, my XML should look like this:

<body>
    <p></p>
    <myTag>
        <p>
            <sectPr></sectPr>
        </p>
        <p></p>
        <p></p>
        <tbl></tbl>
    </myTag>
    <myTag>
        <p>
            <sectPr></sectPr>
        </p>
    </myTag> 
</body>

, , 40 .

: , XSLT, , , , , , XML String , ?

, Visual Basic.

.

0
2

, 40 .

. MSXML, , " " - .

Try:

XSLT 1.0

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

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

<xsl:template match="/body">
    <xsl:copy>
        <!-- start a "chain" for each leading node  -->
        <xsl:apply-templates select="*[1] | *[sectPr]"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="body/*[sectPr]" priority="1">
    <myTag>
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
        <!-- call the next sibling in chain  -->
        <xsl:apply-templates select="following-sibling::*[1][not(sectPr)]"/>
    </myTag>
</xsl:template>

<xsl:template match="body/*">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
    <!-- call the next sibling in chain  -->
    <xsl:apply-templates select="following-sibling::*[1][not(sectPr)]"/>
</xsl:template>

</xsl:stylesheet>
+2

. , , .

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

    <!-- key to select following-sibling of current element containing sectPr, and preceding-sibling of the next element containing sectPr -->
    <xsl:key name="following-sectPr" match="*[not(self::*[sectPr])]" use="generate-id(preceding-sibling::*[sectPr][1])"/>

    <!-- Identity transform template to copy nodes and attributes -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <!-- template to match the elements containing sectPr and add myTag to them and the elements matching the above declared key -->
    <xsl:template match="*[sectPr]">
        <myTag>
            <xsl:apply-templates select="current() | key('following-sectPr', generate-id())" mode="copy"/>
        </myTag>
    </xsl:template>

    <!-- template to do nothing for the elements with no sectPr but having a preceding-sibling elment containing sectPr -->
    <xsl:template match="*[not(sectPr) and preceding-sibling::*[sectPr]]"/>

    <!-- template to copy elements pushed by the template matching *[sectPr] -->
    <xsl:template match="*" mode="copy">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
+2

All Articles