当前位置: 动力学知识库 > 问答 > 编程问答 >

Expand XML depth with XSLT transformation

问题描述:

I'm trying to convert an xml that has a root element and one level deep of child elements. These elements can have the same attribute name. What I am looking for is a way to transform the xml in such a way that the related attributes are nested correctly.

The xml is generated by an HTML form submission (I have control over the form field names).

The resulting XML is generated:

Input.xml

<root>

<project_id>1</project_id>

<project_name>Project 1</project_name>

<project_id>2</project_id>

<project_name>Project 2</project_name>

<project_id>3</project_id>

<project_name>Project 3</project_name>

</root>

Desired output

 <root>

<project>

<id>1</id>

<name>Project 1</name>

</project>

<project>

<id>2</id>

<name>Project 2</name>

</project>

<project>

<id>3</id>

<name>Project 3</name>

</project>

<root>

My Attempt

Note: I prepended 'r_' to the repeated attributes. <r_project_id> 2</r_project_id>

<xsl:template match="/">

<root>

<xsl:apply-templates/>

</root>

</xsl:template>

<xsl:template match="node()|@*">

<project>

<xsl:apply-templates select="*[matches(name(), '^project_')]"/>

</project>

<project>

<xsl:apply-templates select="*[matches(name(), '^r_project')]"/>

</project>

</xsl:template>

<xsl:template match="*[matches(name(), '^r_project_')]">

<xsl:apply-templates select="*[matches(name(), '^r_project_')]"/>

<xsl:copy-of select="*"/>

</xsl:template>

<xsl:template match="*[matches(name(), '^project_')]">

<xsl:element name="{replace(name(), '^project_', '')}">

<xsl:copy-of select="*"/>

</xsl:element>

</xsl:template>

<xsl:template match="*[matches(name(), '^r_project_')]">

<xsl:element name="{replace(name(), '^r_project_', '')}">

<xsl:copy-of select="*"/>

</xsl:element>

</xsl:template>

Output.xml

 <root>

<project>

<id></id>

<name></name>

</project>

<project>

<id></id>

<name></name>

<id></id>

<name></name>

</project>

</root>

Is there a simpler method to creating unique XML elements without having to create a extremely verbose xslt transformation that captures all possible repeated elements?

网友答案:

I can't follow the logic of your XSLT. Is there a reason why this couldn't be simply:

<xsl:template match="/">
<root>
    <xsl:for-each select="root/project_id">
        <project>
            <id><xsl:value-of select="."/></id>
            <name><xsl:value-of select="following-sibling::project_name"/></name>
        </project>
    </xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
网友答案:

The solution from michael.hor257k looks fine, but a slightly more idiomatic and flexible solution in XSLT 2.0 might be

<xsl:template match="/">
<root>
    <xsl:for-each-group select="root/*" group-starting-with="project_id">
        <project>
            <xsl:apply-templates select="current-group()" mode="rename"/>
        </project>
    </xsl:for-each>
</root>
</xsl:template>

<xsl:template match="*" mode="rename">
  <xsl:element name="{substring-after(name(), 'project_')}">
    <xsl:value-of select="."/>
  </xsl:element>
</xsl:template>
分享给朋友:
您可能感兴趣的文章:
随机阅读: