预先确定,我是PHP和Java的新手,但是在过去十年中进入管理层后试图刷新我的编码。
我有一张表格:
heading1_sub1_element1 = data1
heading1_sub1_element2 = data2
heading1_sub1_element3 = data3
heading1_sub2_element1 = data4
heading1_sub2_element2 = data5
heading1_sub2_element3 = data6
使用Tony Marsden's site上的精彩示例,我已经能够将表格提取到表格中:
<table>
<heading1_sub1_element1>data1</heading1_sub1_element1>
<heading1_sub1_element2>data2</heading1_sub1_element2>
<heading1_sub1_element3>data3</heading1_sub1_element3>
<heading1_sub2_element1>data4</heading1_sub2_element1>
<heading1_sub2_element2>data5</heading1_sub2_element2>
<heading1_sub2_element3>data6</heading1_sub2_element3>
</table>
但我想要的是:
<heading1>
<sub1>
<element1>Data1</element1>
<element2>Data2</element2>
<element3>Data3</element3>
</sub1>
<sub2>
<element1>Data4</element1>
<element2>Data5</element2>
<element3>Data6</element3>
</sub2>
</heading1>
有没有人知道如何将数据转换为该格式?我需要使用XSLT,还是PHP可以直接执行此操作?
我这样做的唯一原因是XML看起来整体负载更好。
提前致谢,任何帮助都会得到很好的回复。
答案 0 :(得分:2)
这是一个通用的解决方案,能够正确处理具有指定格式的任何行 - 即使每行上有不同数量的下划线,第一个“名称“在所有行上都不一样:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="my:my" exclude-result-prefixes="my xs">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vLines" select="tokenize(/*, '\r?\n')[.]"/>
<xsl:variable name="vPass1">
<t>
<xsl:apply-templates mode="pass1"/>
</t>
</xsl:variable>
<xsl:template match="/*" mode="pass1">
<xsl:for-each select="$vLines">
<xsl:sequence select="my:makeTree(normalize-space(.))"/>
</xsl:for-each>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:function name="my:makeTree">
<xsl:param name="pLine"/>
<xsl:variable name="vName" select="substring-before($pLine, '_')"/>
<xsl:choose>
<xsl:when test="$vName">
<xsl:element name="{$vName}">
<xsl:sequence select="my:makeTree(substring-after($pLine, '_'))"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name=
"{normalize-space(substring-before($pLine, '='))}">
<xsl:sequence select="substring-after($pLine, '=')"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<xsl:function name="my:group">
<xsl:param name="pNodes" as="node()*"/>
<xsl:for-each-group select="$pNodes[self::*]" group-by="name()">
<xsl:element name="{name()}">
<xsl:for-each select="current-group()">
<xsl:sequence select="my:group(node())"/>
</xsl:for-each>
</xsl:element>
</xsl:for-each-group>
<xsl:copy-of select="$pNodes[not(self::*)]"/>
</xsl:function>
<xsl:template match="*[not(my:path(.) = preceding::*/my:path(.))]" mode="pass2">
<xsl:copy>
<xsl:apply-templates select="//*[my:path(.) = my:path((current()))]/node()"
mode="pass2"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*" mode="pass2"/>
<xsl:template match="/*" mode="pass2" priority="3">
<xsl:apply-templates mode="pass2"/>
</xsl:template>
<xsl:function name="my:path" as="xs:string">
<xsl:param name="pElement" as="element()"/>
<xsl:sequence select=
"string-join($pElement/ancestor-or-self::*/name(.), '/')"/>
</xsl:function>
</xsl:stylesheet>
将此转换应用于以下XML文档(给定的行,包装到顶部元素中以使其成为格式良好的XML文档):
<t>
heading1_sub1_element1 = data1
heading1_sub1_element2 = data2
heading1_sub1_element3 = data3
heading1_sub2_element1 = data4
heading1_sub2_element2 = data5
heading1_sub2_element3 = data6
</t>
产生了想要的正确结果:
<heading1>
<sub1>
<element1> data1</element1>
<element2> data2</element2>
<element3> data3</element3>
</sub1>
<sub2>
<element1> data4</element1>
<element2> data5</element2>
<element3> data6</element3>
</sub2>
</heading1>
将相同的转换应用于此更复杂的XML文档:
<t>
heading1_sub1_element1 = data1
heading1_sub1_element2 = data2
heading1_sub1_element3 = data3
heading1_sub2_element1 = data4
heading1_sub2_element2 = data5
heading1_sub2_element3 = data6
heading2_sub1_sub2_sub3 = data7
heading2_sub1_sub2_sub3_sub4 = data8
heading2_sub1_sub2 = data9
heading2_sub1 = data10
heading2_sub1_sub2_sub3 = data11
</t>
我们再次获得正确的,想要的结果:
<heading1>
<sub1>
<element1> data1</element1>
<element2> data2</element2>
<element3> data3</element3>
</sub1>
<sub2>
<element1> data4</element1>
<element2> data5</element2>
<element3> data6</element3>
</sub2>
</heading1>
<heading2>
<sub1>
<sub2>
<sub3>
data7
<sub4> data8</sub4>
data11
</sub3>
data9
</sub2>
data10
</sub1>
</heading2>
<强>解释强>:
这是一个两遍处理:
.....
<t>
<heading1>
<sub1>
<element1> data1</element1>
</sub1>
</heading1>
<heading1>
<sub1>
<element2> data2</element2>
</sub1>
</heading1>
<heading1>
<sub1>
<element3> data3</element3>
</sub1>
</heading1>
<heading1>
<sub2>
<element1> data4</element1>
</sub2>
</heading1>
<heading1>
<sub2>
<element2> data5</element2>
</sub2>
</heading1>
<heading1>
<sub2>
<element3> data6</element3>
</sub2>
</heading1>
</t>
0.2。在第二遍中,我们执行特定类型的分组,以便生成想要的结果。
注意:在此解决方案中,我们将输入字符串作为XML文档中唯一元素的唯一文本节点子元素。这实际上并不是必需的,我这样做只是为了方便。我们可以使用标准的XSLT 2.0函数 unparsed-text()
从外部文本文件中读取字符串。
答案 1 :(得分:1)
就个人而言,除非你真的与你制作的XML的第一版绑定,否则我将从原始文本文件格式转换并在php中转换整个内容以创建所需的XML。 是的,您可以使用XSL从第一个转换为第二个,但实际上,将这些原始字符串拆分为键值对是一个更简单的过程,然后将其作为常规表达式或字符串拆分,将字符串拆分为'_'字符并将其用作XML结构。 如果你使用
$vals = explode("_", $string_input);
只关键,这将为您提供第一个:
$vals[0] = "heading1";
$vals[1] = "sub1";
$vals[2] = "element1";
你可以用它来制作你想要的结构
我通常不建议有人用字符串创建XML结构(当你遇到编码问题时),但如果你确定不会,只需将其作为字符串输出(或者如同其他答案所说,的SimpleXML)。
答案 2 :(得分:0)
我很确定你必须做一些字符串操作来解析你想要的节点名称,但之后再看看PHP的simpleXML。这是一个显示如何使用它的good answer。