需求:使用高级XSLT实现XML到XML的转换(附示例XML)
Got it, let's work through this. Your input XML has a <root> containing multiple <name> nodes, each with <elements> tagged with a type (T attribute) and sequence number (S attribute). Since you didn't specify the exact target XML structure you need, I'll walk through a common, flexible transformation that groups elements by their T attribute within each <name>—this is easy to adapt to your specific output requirements.
Input XML
<root> <name> <elements T="BI" S="1">1</elements> <elements T="BI" S="2">2</elements> <elements T="BI" S="3">3</elements> </name> <name> <elements T="BM" S="1">10</elements> <elements T="BM" S="2">20</elements> <elements T="BM" S="3">30</elements> </name> <name> <elements T="XX" S="1">001</elements> <elements T="XX" S="2">002</elements> </name> </root>
Sample Target Output
Let's say we want to restructure each <name> into a <data-group> where each unique type (T) gets its own container with sequence items:
<root> <data-group> <type id="BI"> <sequence number="1">1</sequence> <sequence number="2">2</sequence> <sequence number="3">3</sequence> </type> </data-group> <data-group> <type id="BM"> <sequence number="1">10</sequence> <sequence number="2">20</sequence> <sequence number="3">30</sequence> </type> </data-group> <data-group> <type id="XX"> <sequence number="1">001</sequence> <sequence number="2">002</sequence> </type> </data-group> </root>
XSLT Code (2.0+)
This uses XSLT 2.0's grouping features, which are widely supported in modern processors (like Saxon, Xalan, or built-in tools in Java/.NET):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- Identity template: copy all nodes/attributes by default --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- Transform <name> to <data-group> --> <xsl:template match="name"> <data-group> <!-- Group <elements> by their T attribute --> <xsl:for-each-group select="elements" group-by="@T"> <type id="{current-grouping-key()}"> <!-- Process each element in the group --> <xsl:for-each select="current-group()"> <sequence number="{@S}"> <xsl:value-of select="."/> </sequence> </xsl:for-each> </type> </xsl:for-each-group> </data-group> </xsl:template> </xsl:stylesheet>
Key Explanations
- Identity Template: This is the foundation of most XSLT transformations—it copies everything from the input unless we override it with a specific template. That means any parts of your XML not mentioned in other templates (like the
<root>element) will stay as-is. - Grouping with
xsl:for-each-group: This is the "advanced" part you mentioned. It groups all<elements>under a<name>by theirTattribute.current-grouping-key()gives us the value ofTfor the current group (like "BI" or "BM"). - Dynamic Attribute Values: We use curly braces
{}to insert attribute values directly from the input (e.g.,id="{current-grouping-key()}"takes theTvalue and puts it into theidattribute of<type>).
Adapting to Your Exact Needs
If your target structure is different, just modify the templates:
- If you want to keep
<name>instead of<data-group>, remove the<data-group>wrapper and adjust the template match to just process the children. - If you need a flat structure (no grouping by
T), skip thexsl:for-each-groupand just transform each<elements>directly to your desired element. - If you need to filter certain
Tvalues, add awhereclause to thexsl:for-each-group(e.g.,group-by="@T" where @T != 'XX').
内容的提问来源于stack exchange,提问作者qubiter

