1

好的,我是 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 网站上的精彩示例,我已经能够获取表格以将数据提取到表单中:

<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 看起来更好。

在此先感谢您,我们将不胜感激任何帮助。

4

3 回答 3

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>

说明

这是一个两遍处理:

  1. 在 pass1 中,我们将输入转换为一个临时树(在上面的第一个 XML 文档的情况下),如下所示:

......

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

.2. 在第二遍中,我们执行特定类型的分组,以便产生想要的结果。

注意:在这个解决方案中,我们将输入字符串作为 XML 文档中唯一元素的唯一文本节点子节点来访问。这实际上是不必要的,我这样做只是为了方便。我们可以使用标准 XSLT 2.0 函数从外部文本文件中读取字符串unparsed-text()

于 2012-05-25T04:21:52.497 回答
1

就个人而言,除非您真的与您制作的 XML 的第一个版本相关联,否则我只会从原始文本文件格式开始,并将整个内容转换为 php 以创建您想要的 XML。是的,您可以使用 XSL 从第一个转换为第二个,但实际上,将这些原始字符串拆分为键值对,然后作为常规表达式或字符串拆分,拆分字符串在'_' 字符并将其用作 XML 结构。如果你使用

$vals = explode("_", $string_input);

仅在关键上,这将为您提供第一个:

$vals[0] = "heading1";
$vals[1] = "sub1";
$vals[2] = "element1";

你可以用它来制作你想要的结构

我通常不会建议某人使用字符串制作 XML 结构(当您遇到编码问题时),但如果您确定不会,只需将其作为字符串输出(或者如其他答案所说,simpleXML)。

于 2012-05-23T15:57:07.410 回答
0

我很确定您必须执行一些字符串操作来解析出您想要的节点名称,但之后查看 PHP 的 simpleXML。这是一个很好的答案,展示了如何使用它。

于 2012-05-23T15:10:17.117 回答