2013-02-09 1 views
1

Я совершенно не знаком с xslt. Пожалуйста, помогите мне написать sheet.I стиль есть входной XML, как этотxml to xml using xslt: Рекурсивное сопоставление и создание иерархии, например дерева

Входной XML:

<elements> 
    <e1> 
     <pid>1</pid> 
     <cid>2</cid> 
    </e1> 

    <e1> 
     <pid>1</pid> 
     <cid>3</cid> 
    </e1> 

    <e1> 
     <pid>2</pid> 
     <cid>4</cid> 
    </e1> 
    </elements> 

Желаемая XML:

<tree> 
     <unit id="1"> 
     <unit id="2"> 
      <unit id="4"> 
      <data></data> 
      </unit> 
      <data></data> 
     </unit> 

     <unit id="3"> 
      <data></data> 
     </unit> 

     <data></data> 

     </unit> 
    </tree> 

Я чувствую, что это должно быть очень легко, но я изо всех сил чтобы найти информацию о том, как это сделать. Знания XSLT невелики.

ответ

3

Я не уверен на 100%, как вы хотите, чтобы XSLT определял из этого ввода, что верхний идентификатор равен 1 (это потому, что это единственное значение pid без соответствующих значений cid, или это всегда 1?). Тем не менее, это должно сделать работу:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:key name="kItemsByC" match="e1" use="cid" /> 
    <xsl:key name="kItemsByP" match="e1" use="pid" /> 

    <xsl:template match="/"> 
    <tree> 
     <xsl:call-template name="Unit"> 
     <!-- This will be the value of the <pid> that has no <cid> references to 
      it (assuming there is only one top-level <pid>) --> 
     <xsl:with-param name="id" 
         select="string(/elements/e1/pid[not(key('kItemsByC', .))])" /> 
     </xsl:call-template> 
    </tree> 
    </xsl:template> 

    <xsl:template match="e1" name="Unit"> 
    <xsl:param name="id" select="cid" /> 

    <unit id="{$id}"> 
     <xsl:apply-templates select="key('kItemsByP', $id)" /> 
     <data /> 
    </unit> 
    </xsl:template> 
</xsl:stylesheet> 

Когда это будет работать на вашем входе образца, это производит:

<tree> 
    <unit id="1"> 
    <unit id="2"> 
     <unit id="4"> 
     <data /> 
     </unit> 
     <data /> 
    </unit> 
    <unit id="3"> 
     <data /> 
    </unit> 
    <data /> 
    </unit> 
</tree> 

Примечание: выше XSLT имеет логику, чтобы попытаться динамически определить верхний ID уровня. Если можно предположить, что устройство верхнего уровня всегда будет иметь идентификатор 1, то один ключ и (несколько) сложная формула, приведенные выше XSLT могут быть устранены:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:key name="kItemsByP" match="e1" use="pid" /> 

    <xsl:template match="/"> 
    <tree> 
     <xsl:call-template name="Unit"> 
     <xsl:with-param name="id" select="1" /> 
     </xsl:call-template> 
    </tree> 
    </xsl:template> 

    <xsl:template match="e1" name="Unit"> 
    <xsl:param name="id" select="cid" /> 

    <unit id="{$id}"> 
     <xsl:apply-templates select="key('kItemsByP', $id)" /> 
     <data /> 
    </unit> 
    </xsl:template> 
</xsl:stylesheet> 

Это также производит требуемый выход при запуске на вашем образец ввод.

0

Ah, после прочтения JLRishe Я думаю, что получаю: «pid» означает «родительский идентификатор», «cid» означает «идентификатор ребенка», а e1 представляет отношения родитель-потомок. Блестящая детективная работа, я бы никогда не справился с этим сам.

Основная модель заключается в том, что когда вы находитесь на родительском элементе, вы применяете шаблоны к своим дочерним элементам. Это также справедливо, если отношения между родителями и дочерними элементами представлены первичными/внешними ключами, как при их представлении с использованием иерархии XML. Таким образом, суть такова:

<xsl:template match="e1"> 
    <unit id="{pid}"> 
    <xsl:apply-templates select="//e1[pid=current()/cid]"/> 
    <data/> 
    </unit> 
</xsl:template> 

, который по сути является решением JLRishe, за исключением того, что он добавил оптимизацию с использованием ключей.