2015-04-26 1 views
0

У меня довольно большой XML-файл размером около 3-4 МБ, и мне нужно обернуть некоторые элементы внутри тегов. Мой Xml имеет следующую структуру:Большой XML-файл - оберните элементы внутри тегов с помощью XSLT или манипулируя XML как String?

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

Конечно, все p и tbl элементов будут повторяться внутри body до конца файла (также каждый из элементов, представленных выше, будет иметь ребенок, - я просто взял их для простоты). В качестве оценки у меня будет около 70 элементов, содержащих sectPr внутри body, не обязательно в том порядке, который я описал выше.

Что бы я хотел сделать, это обернуть все элементы, которые начинаются с элемента, содержащего sectPr, следующему элементу, содержащему sectPr в другой тег. В результате, мой XML должен выглядеть следующим образом:

<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

Какую версию XSLT вы используете? Может ли быть более потомок 'sectPr' элементов внутри' sectPr'? Если бы вы хотели бы добавить еще один тег? –

+0

должен добавить визуальный базовый тег – amdixon

+0

Я использую XSLT 1.0, и только p элементы могут иметь либо не более, либо не более одного sectPr внутри них. Кроме того, sectPr не имеет детей. – Andy

ответ

2

другое требование заключается в том, что операция должна быть выполнена под 40 секунд.

Производительность зависит в большой степени от конкретного используемого процессора. Если вы используете MSXML, вы можете значительно выиграть, используя так называемую «рекурсию сестры» в этом сценарии - as shown recently by Dimitre Novatchev.

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> 
+0

Благодарим за решение, но могу ли я спросить вас, как это работает? Я хотел бы понять это лучше. – Andy

+2

Ухм, я думал, что комментарии достаточно толковые. Общая идея заключается в применении шаблонов (из контекста 'body') только к узлам с дочерним элементом' sectPr'. Каждый из них открывает «myTag», копирует себя в него и приглашает сразу следующего брата, чтобы войти - при условии, что у него нет собственного «sectPr». –

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> 
Смежные вопросы