问题
I have an XML schema that I need to extract values from but I am not having much luck.
The souce schema is:
<Reading>
<State>
<StateValues>
<Name>
<Value>
</StateValues>
</State>
<Reading>
An example of the XML would be:
<Reading>
<State>
<StateValues>
<Name>Reading1</Name>
<Value>1234</Value>
</StateValues>
<StateValues>
<Name>Reading2</Name>
<Value>2345</Value>
</StateValues>
</State>
<State>
<StateValues>
<Name>Reading3</Name>
<Value>4321</Value>
</StateValues>
</State>
<Reading>
I need a result that is:
<Readings>
<Reading1>1234</Reading1>
<Reading2>2345</Reading2>
<Reading3>4321</Reading3>
</Readings>
I have no control over the schemas.
I have been trying to use a xsl:foreach
with an xsl:if
that checks the name but I just get the first value repeated 3 times. Any tips? I've been trying to figure this out for 2 days and I am not an XSLT expert...
Thanks. EDIT : Sorry for not posting my XSLT. I had tried several versions and didn't think it would be useful. Here it is:
Blockquote
<xsl:element name="ns0:Readings">
<xsl:element name="ns0:Current">
<xsl:for-each select="/*[local-name()='gatewayInterface' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Reading' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='State' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='StateValues' and namespace-uri()='http://biztalk.gateway.com']">
<xsl:choose>
<xsl:when test="Name='TOTAL'">
<xsl:element name="ns0:Total">
<xsl:value-of select="/*[local-name()='gatewayInterface' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Reading' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='State' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='StateValues' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Name' and namespace-uri()='http://biztalk.gateway.com']/text()='Total'" />
</xsl:element>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="/*[local-name()='gatewayInterface' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Reading' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='State' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='StateValues' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Name' and namespace-uri()='http://biztalk.gateway.com']/text()='Reading1'">
<xsl:element name="ns0:Reading1">
<xsl:value-of select="/*[local-name()='gatewayInterface' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Reading' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='State' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='StateValues' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Name' and namespace-uri()='http://biztalk.gateway.com']/text()" />
</xsl:element>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="/*[local-name()='gatewayInterface' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Reading' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='State' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='StateValues' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Name' and namespace-uri()='http://biztalk.gateway.com']/text() = 'Reading2'">
<xsl:element name="ns0:Reading2">
<xsl:value-of select="/*[local-name()='gatewayInterface' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Reading' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='State' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='StateValues' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Name' and namespace-uri()='http://biztalk.gateway.com']/text()" />
</xsl:element>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="/*[local-name()='gatewayInterface' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Reading' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='State' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='StateValues' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Name' and namespace-uri()='http://biztalk.gateway.com']/text() = 'Reading3'">
<xsl:element name="ns0:Reading3">
<xsl:value-of select="/*[local-name()='gatewayInterface' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Reading' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='State' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='StateValues' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Name' and namespace-uri()='http://biztalk.gateway.com']/text()" />
</xsl:element>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="/*[local-name()='gatewayInterface' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Reading' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='State' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='StateValues' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Name' and namespace-uri()='http://biztalk.gateway.com']/text() = 'Reading4'">
<xsl:element name="ns0:Reading4">
<xsl:value-of select="/*[local-name()='gatewayInterface' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Reading' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='State' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='StateValues' and namespace-uri()='http://biztalk.gateway.com']/*[local-name()='Name' and namespace-uri()='http://biztalk.gateway.com']/text()" />
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:element>
回答1:
foreach
and if
are usually the wrong approach in XSLT. It is far more effective to apply templates to patterns. In this case you can use two: the first sets up the root element and matches the elements you want to work with:
<xsl:template match='/'>
<Readings>
<xsl:apply-templates select='Reading/State/StateValues'/>
</Readings>
</xsl:template>
and a second that the above triggers when a match is found that will do the core work. The complexity here is creating an element dynamically which means using the {XPath}
syntax to get the name from the input document:
<xsl:template match='StateValues'>
<xsl:element name='{Name}'>
<xsl:value-of select='Value' />
</xsl:element>
</xsl:template>
来源:https://stackoverflow.com/questions/6014831/xslt-foreach-repeating-nodes-to-flat