动态创建XML节点的XSLT需求:补全缺失层级子节点
Solution to Auto-Complete Missing XML Hierarchy Nodes with XSLT
To solve this problem, we need to ensure every AWARDLINE node has the full hierarchy of SHIPMENT → ACCOUNT → ASSOCIATEDREQ nodes, creating empty nodes for any missing levels. Here's a straightforward XSLT implementation that handles each layer of the hierarchy:
Source XML
<AWARD> <FIELD1>XYZ</FIELD1> <AWARDLINE> <ALINENUM>1</ALINENUM> <SHIPMENT> <SHIPLINENUM>1.1</SHIPLINENUM> <ACCOUNT> <ACCOUNTLINENUM>1.1.1</ACCOUNTLINENUM> <ASSOCIATEDREQ> <AREQNUM>1.1.1.1</AREQNUM> </ASSOCIATEDREQ> </ACCOUNT> </SHIPMENT> </AWARDLINE> <AWARDLINE> <ALINENUM>2</ALINENUM> </AWARDLINE> </AWARD>
Desired Output XML
<AWARD> <FIELD1>XYZ</FIELD1> <AWARDLINE> <ALINENUM>1</ALINENUM> <SHIPMENT> <SHIPLINENUM>1.1</SHIPLINENUM> <ACCOUNT> <ACCOUNTLINENUM>1.1.1</ACCOUNTLINENUM> <ASSOCIATEDREQ> <AREQNUM>1.1.1.1</AREQNUM> </ASSOCIATEDREQ> </ACCOUNT> </SHIPMENT> </AWARDLINE> <AWARDLINE> <ALINENUM>2</ALINENUM> <SHIPMENT> <ACCOUNT> <ASSOCIATEDREQ/> </ACCOUNT> </SHIPMENT> </AWARDLINE> </AWARD>
XSLT Code
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- Identity template: copy all existing nodes/attributes as-is --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- Ensure AWARDLINE has a SHIPMENT node (create empty if missing) --> <xsl:template match="AWARDLINE"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> <xsl:if test="not(SHIPMENT)"> <SHIPMENT> <xsl:apply-templates select="SHIPMENT/@*|SHIPMENT/node()"/> </SHIPMENT> </xsl:if> </xsl:copy> </xsl:template> <!-- Ensure SHIPMENT has an ACCOUNT node (create empty if missing) --> <xsl:template match="SHIPMENT"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> <xsl:if test="not(ACCOUNT)"> <ACCOUNT> <xsl:apply-templates select="ACCOUNT/@*|ACCOUNT/node()"/> </ACCOUNT> </xsl:if> </xsl:copy> </xsl:template> <!-- Ensure ACCOUNT has an ASSOCIATEDREQ node (create empty if missing) --> <xsl:template match="ACCOUNT"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> <xsl:if test="not(ASSOCIATEDREQ)"> <ASSOCIATEDREQ/> </xsl:if> </xsl:copy> </xsl:template> </xsl:stylesheet>
How It Works
- Identity Template: This is the base template that copies all existing XML content exactly as it is, preserving nodes and attributes that are already present.
- AWARDLINE Template: Checks if the
AWARDLINEhas aSHIPMENTchild. If not, it creates an emptySHIPMENTnode and applies templates to any existing (though in this case, none) content inside it. - SHIPMENT Template: Similarly, checks for an
ACCOUNTchild. If missing, creates an emptyACCOUNTnode. - ACCOUNT Template: Checks for an
ASSOCIATEDREQchild. If missing, creates an emptyASSOCIATEDREQnode.
This layered approach ensures that every level of the hierarchy is completed, regardless of which nodes are missing in the source XML. It works for any combination of missing nodes (e.g., AWARDLINE has SHIPMENT but no ACCOUNT, or ACCOUNT exists but no ASSOCIATEDREQ).
内容的提问来源于stack exchange,提问作者Nagaraj Rao
相关产品推荐
相关产品推荐

