2012-02-21 3 views
1

Какова будет (желательно наиболее эффективный) способ лучше всего, чтобы сделать следующее:Преобразование родового XML-документа с помощью XPath/XSLT

Рассмотрим У меня есть документ XML, как например:

<comments question_id="123"> 
    <comment id="1"> 
     This is the first comment 
    </comment> 
    <comment id="2"> 
     This is the second comment 
    </comment> 
</comments> 

сейчас , учитывая, что я указать «путь» к каждому блоку данных в, то есть в данном случае:

path: /comments/comment

Я хотел бы разбить документ на п-NUM Бер из подразделов, в данном случае 2: ​​

<comments question_id="123"> 
    <comment id="1"> 
     This is the first comment 
    </comment> 
</comments> 

<comments question_id="123"> 
    <comment id="2"> 
     This is the second comment 
    </comment> 
</comments> 

Так, по существу, что я пытаюсь сделать, это получить каждый узел произведенного “/comments/comment”, но и сохранить все данные родительские узлы «внешних».

EDIT:

Примечание: это должно быть динамичным, или общий. То есть приведенные выше данные xml являются лишь примером. Я хочу, чтобы иметь возможность преобразовать любой XML-документ с этим эффектом, учитывая «путь», представляющий каждый узел данных. Остальное - внешнее тело xml.

+0

XPath позволяет для выбора узлов в существующем документе, а не для его преобразования. Для этой задачи вы используете XSLT, а не XPath. Вы хотите использовать XSLT? Вам нужны несколько выходных документов? Или просто все эти фрагменты объединены в одном документе? –

+0

@MartinHonnen Спасибо за ваш комментарий. Я не против использования Xslt, поэтому я отредактировал вопрос на этот счет. Мне бы хотелось четыре отдельных документа. – Larry

+0

@ Larry: Да, существует общее решение. –

ответ

0

Родового "измельчения" решение можно найти в моем ответе на этот вопрос: https://stackoverflow.com/a/8597577/36305

Адрес: mplete преобразование:

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

    <xsl:param name="pLeafNodes" select="//comment"/> 

    <xsl:template match="/"> 
     <t> 
     <xsl:call-template name="StructRepro"/> 
     </t> 
    </xsl:template> 

    <xsl:template name="StructRepro"> 
     <xsl:param name="pLeaves" select="$pLeafNodes"/> 

     <xsl:for-each select="$pLeaves"> 
     <xsl:apply-templates mode="build" select="/*"> 
      <xsl:with-param name="pChild" select="."/> 
      <xsl:with-param name="pLeaves" select="$pLeaves"/> 
     </xsl:apply-templates> 
     </xsl:for-each> 
    </xsl:template> 

     <xsl:template mode="build" match="node()|@*"> 
      <xsl:param name="pChild"/> 
      <xsl:param name="pLeaves"/> 

     <xsl:copy> 
      <xsl:apply-templates mode="build" select="@*"/> 

      <xsl:variable name="vLeafChild" select= 
      "*[count(.|$pChild) = count($pChild)]"/> 

      <xsl:choose> 
      <xsl:when test="$vLeafChild"> 
      <xsl:apply-templates mode="build" 
       select="$vLeafChild 
         | 
          node()[not(count(.|$pLeaves) = count($pLeaves))]"> 
       <xsl:with-param name="pChild" select="$pChild"/> 
       <xsl:with-param name="pLeaves" select="$pLeaves"/> 
      </xsl:apply-templates> 
      </xsl:when> 
      <xsl:otherwise> 
      <xsl:apply-templates mode="build" select= 
      "node()[not(.//*[count(.|$pLeaves) = count($pLeaves)]) 
        or 
        .//*[count(.|$pChild) = count($pChild)] 
        ] 
      "> 

       <xsl:with-param name="pChild" select="$pChild"/> 
       <xsl:with-param name="pLeaves" select="$pLeaves"/> 
      </xsl:apply-templates> 
      </xsl:otherwise> 
      </xsl:choose> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="text()"/> 
</xsl:stylesheet> 

Когда это преобразование применяется на поставленном XML документа:

<comments question_id="123"> 
    <comment id="1"> 
     This is the first comment 
    </comment> 
    <comment id="2"> 
     This is the second comment 
</comment> 
</comments> 

разыскиваемый, правильный результат получается:

<t> 
    <comments question_id="123"> 
     <comment id="1"> 
     This is the first comment 
    </comment> 
    </comments> 
    <comments question_id="123"> 
     <comment id="2"> 
     This is the second comment 
</comment> 
    </comments> 
</t> 
+0

Большое спасибо, это выглядит отлично. Один вопрос: такова единственная переменная в этом коде, где мы указываем 'select =" // comment "'?Если бы я хотел, чтобы это было полностью общим, так как я хотел применить это преобразование к серии XML-документов из Java, как лучше всего это сделать? – Larry

+0

@Larry: Это не переменная - это глобальный параметр 'xsl: param', и его основная цель - именно то, что вы просите, - что он может быть установлен извне программой, которая вызывает преобразование. Как параметр для преобразования задан, зависит от реализации. Вы должны прочитать документацию своего XSLT-процессора. Я знаю, как это сделать для .NET XslCompiledTransform или для MSXML или для Saxon. –

+0

Хорошо спасибо, я понимаю сейчас. – Larry

0

Если вы actuall хотите превратить ваш Xml с помощью XSLT это должно выглядеть следующим образом:

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

    <xsl:template match="/"> 
     <!-- You need a document root to produce valid Xml output --> 
     <yourdocumentroot> 
      <xsl:apply-templates /> 
     </yourdocumentroot> 
    </xsl:template> 

    <xsl:template match="comments"> 
     <xsl:apply-templates /> 
    </xsl:template> 

    <xsl:template match="comment"> 
     <xsl:element name="comments"> 
      <xsl:attribute name="question_id"> 
       <xsl:value-of select="ancestor::comments/@question_id"/> 
      </xsl:attribute> 
      <xsl:element name="comment"> 
       <xsl:attribute name="id"> 
        <xsl:value-of select="./@id" /> 
       </xsl:attribute> 
       <xsl:value-of select="./text()" /> 
      </xsl:element> 
     </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

... даст вам желаемый результат:

<?xml version="1.0" encoding="utf-8"?> 
<yourdocumentroot> 
    <comments question_id="123"> 
     <comment id="1">This is the first comment</comment> 
    </comments> 
    <comments question_id="123"> 
     <comment id="2">This is the second comment</comment> 
    </comments> 
</yourdocumentroot> 
+0

Спасибо, но я забыл упомянуть, я хотел что-то общее. Теперь я отредактировал это в своем вопросе. Не могли бы вы обновить свой ответ, чтобы включить это. – Larry

Смежные вопросы