Check existence of child node and applying templates
I have the following simplified XML structure:
<?xml version="1.0" encoding="UTF-8"?>
<ExportData>
<TransportHeader>
<Timestamp>2011-01-16 06:00:33</Timestamp>
<From>
<Name>DynamicExport</Name>
<Version>1.</Version>
</From>
<MessageId>d7b5c5b69a83</MessageId>
</TransportHeader>
<ExportConfig>
<DateTimeFormat>yyyy-MM-dd HH:mm:ss</DateTimeFormat>
<DecimalSymbol>.</DecimalSymbol>
</ExportConfig>
<DataSet>
<Tables>
<Table>
<RH>...</RH>
<Rows>
<R>Data1</R>
<R>Data2</R>
<R>Data3</R>
<R>Data4</R>
<R>Data5</R>
</Rows>
</Table>
</Tables>
</DataSet>
</ExportData>
I have to check if <R>
elements exist or not. If no <R>
elements exist the mapping has to be aborted, otherwise a <Line>
element per <R>
needs to be created.
I came up with this solution which works perfectly so far:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output encoding="ISO-8859-1" method="xml" indent="yes" />
<!-- suppress nodes that are not matched -->
<xsl:template match="text() | @*">
<xsl:apply-templates select="text() | @*"/>
</xsl:template>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="not(ExportData/DataSet/Tables/Table/Rows/node())">
<xsl:message terminate="yes">No line items</xsl:message>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/ExportData/DataSet/Tables/Table/Rows">
<INVOIC02>
<!-- apply LINE ITEMS template -->
<xsl:apply-templates select="R"/>
</INVOIC02>
</xsl:template>
<!-- Template creating LINE ITEMS -->
<xsl:template match="R">
<Line>
<elements></elements>
</Line>
</xsl:template>
</xsl:stylesheet>
If there are <R>
elements the output is this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<INVOIC02>
<Line开发者_运维问答>
<elements/>
</Line>
<Line>
<elements/>
</Line>
<Line>
<elements/>
</Line>
<Line>
<elements/>
</Line>
<Line>
<elements/>
</Line>
</INVOIC02>
If there is just <Rows/>
and no <R>
s the mapping is aborted.
Now I have two questions:
-Is my test for <R>
elements robust: test="not(ExportData/DataSet/Tables/Table/Rows/node())"
?
-I am using <xsl:apply-templates>
to create the <Line>
items instead of an <xsl:for-each>
construct. Are my XPath expressions okay or could I make them better?
Is my test for elements robust: test="not(ExportData/DataSet/Tables/Table/Rows/node())" ?
Well, do you want it to fail if there are no R
elements, or fail if Rows
does not have a child node()
, which would include any element (not just R
), text()
, comment()
or processing-instruction()
?
If you really want to verify that there is at least one R
element that is a child of Rows
, you should adjust the test criteria to be more specific:
test="not(ExportData/DataSet/Tables/Table/Rows/R)"
Otherwise, it may pass that test and continue processing and not generate the content you want.
I am using <xsl:apply-templates> to create the <Line> items instead of an <xsl:for-each> construct. Are my XPath expressions okay or could I make them better?
You could get rid of the <xsl:if>
conditional logic inside of your template for the root node and move that logic into a template for Rows
that don't contain R
children. Putting logic into xsl:template
@match
criteria makes it easier for XSLT processors to optimize, which can lead to performance gains.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output encoding="ISO-8859-1" method="xml" indent="yes" />
<!-- suppress nodes that are not matched -->
<xsl:template match="text() | @*">
<xsl:apply-templates select="text() | @*"/>
</xsl:template>
<!--All Rows must contain an R.
If we encounter any that do not, terminate the transform -->
<xsl:template match="/ExportData/DataSet/Tables/Table/Rows[not(R)]">
<xsl:message terminate="yes">No line items</xsl:message>
</xsl:template>
<!--match for Rows that have R children -->
<xsl:template match="/ExportData/DataSet/Tables/Table/Rows[R]">
<INVOIC02>
<!-- apply LINE ITEMS template -->
<xsl:apply-templates select="R"/>
</INVOIC02>
</xsl:template>
<!-- Template creating LINE ITEMS -->
<xsl:template match="R">
<Line>
<elements></elements>
</Line>
</xsl:template>
</xsl:stylesheet>
This will check whether R node has child element:
<xsl:if test="R">
<!--What you want to do here-->
</xsl:if>
精彩评论