Преобразовать структуру XML в другую структуру XML - PullRequest
1 голос
/ 06 сентября 2010

Я работаю с PHP5, и мне нужно преобразовать XML в следующую форму:

<item>
    <string isNewLine="1" lineNumber="32">some text in new line</string>
    <string>, more text</string>
    <item>
        <string isNewLine="1" lineNumber="33">some text in new line</string>
        <string isNewLine="1" lineNumber="34">some text</string>
        <string> in the same line</string>
        <string isNewLine="1" lineNumber="35">some text in new line</string>
    </item>
</item>

примерно так:

<item>
    <line lineNumber="32">some text in new line, more text</string>
    <item>
            <line lineNumber="33">some text in new line</string>
            <line lineNumber="34">some text in the same line</string>
            <line lineNumber="35">some text in new line</string>
    </item>
</item>

Как видите, он объединил текст, содержащийся в нескольких «строковых» узлах. Также обратите внимание, что узлы 'string' могут быть вложены в другие узлы любого уровня.

Каковы возможные решения для преобразования исходного XML в целевой XML?

Спасибо

Ответы [ 4 ]

2 голосов
/ 06 сентября 2010

Эта таблица стилей производит вывод, который вы ищете:

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

    <!--Identity template simply copies content forward by default -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="string[@isNewLine and @lineNumber]">
        <line>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="text()" />
            <!-- Include the text() from the string elements that come after this element,
                do not have @isNewLine or @lineNumber,
                and are only following this particular element -->
            <xsl:apply-templates select="following-sibling::string[not(@isNewLine and @lineNumber) and generate-id(preceding-sibling::string[1]) = generate-id(current())]/text()" />
        </line>
    </xsl:template>

    <!--Suppress the string elements that do not contain isNewLine or lineNumber attributes in normal processing-->
    <xsl:template match="string[not(@isNewLine and @lineNumber)]" />

    <!--Empty template to prevent attribute from being copied to output-->
    <xsl:template match="@isNewLine" />

</xsl:stylesheet>
2 голосов
/ 06 сентября 2010

Вот эффективное и правильное решение :

<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:key name="knextStrings"
   match="string[not(@isNewLine)]"
   use="generate-id(preceding-sibling::string
                                 [@isNewLine][1]
                    )"/>


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

 <xsl:template match="string[@isNewLine]">
  <line>
   <xsl:copy-of select="@*[not(name()='isNewLine')]"/>
   <xsl:copy-of select="text()
                       |
                        key('knextStrings',
                             generate-id()
                             )
                              /text()"/>
  </line>
 </xsl:template>

 <xsl:template match="string[not(@isNewLine)]"/>
</xsl:stylesheet>

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

<item>
    <string isNewLine="1" lineNumber="32">some text in new line</string>
    <string>, more text</string>
    <item>
        <string isNewLine="1" lineNumber="33">some text in new line</string>
        <string isNewLine="1" lineNumber="34">some text</string>
        <string> in the same line</string>
        <string isNewLine="1" lineNumber="35">some text in new line</string>
    </item>
</item>

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

<item>
  <line lineNumber="32">some text in new line, more text</line>
  <item>
    <line lineNumber="33">some text in new line</line>
    <line lineNumber="34">some text in the same line</line>
    <line lineNumber="35">some text in new line</line>
  </item>
</item>
0 голосов
/ 09 сентября 2010

Использовать XSL-преобразование.

Из документации PHP :

<?php

$xml = new DOMDocument;
$xml->load('data.xml');

$xsl = new DOMDocument;
$xsl->load('trans.xsl');

$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);

echo $proc->transformToXML($xml);

?>

Используйте ответ Дмитрия для trans.xsl.

0 голосов
/ 06 сентября 2010

Вы должны посмотреть на парсер XML для этого. Вы можете использовать синтаксический анализатор на основе SAX или DOM.

SAX более эффективен, но DOM может лучше удовлетворить ваши потребности, так как с ним легче работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...