将xml结构转换为另一个xml结构

时间:2010-09-06 11:13:13

标签: php xml xslt

我正在使用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>

正如您所看到的,它已加入多个“字符串”节点中包含的文本。 另请注意,“字符串”节点可以嵌套在任何级别的其他节点中。

将源xml转换为目标xml有哪些可能的解决方案?

谢谢,

4 个答案:

答案 0 :(得分:2)

此样式表生成您要查找的输出:

<?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>

答案 1 :(得分:2)

这是一个有效且正确的解决方案

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

答案 2 :(得分:0)

您应该为此查看XML Parser。您可以使用基于SAX或基于DOM的解析器。

SAX效率更高,但DOM可以更好地满足您的需求,因为它更容易使用。

答案 3 :(得分:0)

使用XSL转换。

来自PHP documentation

<?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);

?>

使用Dimitri对trans.xsl的回答。