2012-05-23 3 views
1

OK upfront, я новичок на PHP и Java, но пытаюсь обновить свою кодировку после перехода в управление в течение последних десяти лет.Как разделить строку с разделителем на узел XML Tree

У меня есть таблица в виде:

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

Является ли заголовок всегда '', или есть ли количество заголовков, которые должны быть заключены в корневой узел? – Borodin

ответ

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().

0

Я уверен, что вам придется выполнять некоторые строковые операции, чтобы проанализировать имена узлов, которые вы хотите, но после этого посмотрите на простой XML-код PHP. Вот good answer, который показывает, как его использовать.

1

Лично, если вы действительно не привязаны к первой версии XML, которую вы сделали, я бы просто перешел из исходного формата текстового файла и преобразовал все это в php, чтобы создать необходимый XML. Да, вы можете использовать XSL для преобразования от первого ко второму, но на самом деле это гораздо более простой процесс разбивки этих исходных строк на пары значений ключа, а затем либо в виде регулярного выражения, либо в результате разделения строк, разделите строку на символ «_» и использовать это как структуру XML. Если вы используете

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

только на ключ, который даст Вам для первого:

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

, которые вы могли бы использовать, чтобы сделать структуру, которую вы хотите

я обычно никогда посоветуйте кому-либо создать структуру XML со строкой (при запуске в проблемы с кодировкой), но если вы уверены, что не хотите, просто выведите ее как строку (или, как говорит другой ответ, simpleXML).

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