The XML I'm trying to transform looks as follows. I can't post the actual file as it contains sensitive information.
我要转换的XML如下所示。我不能发布实际文件,因为它包含敏感信息。
<?xml version="1.0" encoding="utf-16"?>
<TimesheetDetails>
<timeAllocations>
<TimeAllocationEntryDetails>
<activity>
<displayText> Value </displayText>
</activity>
</TimeAllocationEntryDetails>
<TimeAllocationEntryDetails>
<activity>
<displayText> Value </displayText>
</activity>
</TimeAllocationEntryDetails>
<TimeAllocationEntryDetails>
<activity>
<displayText> Value </displayText>
</activity>
</TimeAllocationEntryDetails>
<TimeAllocationEntryDetails>
<activity>
<displayText> Value </displayText>
</activity>
</TimeAllocationEntryDetails>
</timeAllocations>
</TimesheetDetais>
Here's a simple XSLT stylesheet I wrote to extract the data from the child nodes. It works as expected, however it only returns data from ONE of the TimesheetEntryDetails
下面是我编写的一个简单的XSLT样式表,用于从子节点中提取数据。它按照预期工作,但是它只返回一个时间表细节中的数据
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/TimeSheetDetails">
<xsl:apply-templates select="timeAllocations"/>
</xsl:template>
<xsl:template match="timeAllocations">
<xsl:for-each select="TimeAllocationEntryDetails">
<xsl:for-each select=".">
<DisplayText>
<xsl:value-of select="displayText"/>
</DisplayText>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
My expected output should look something like
我的期望输出应该是这样的
<DisplayText>
SomeData
</DisplayText>
one for each TimeSheetAllocationEntryDetails node under timeheetAllocations.
在timeheetallocationentrydetails节点下的每个时间表。
Any help appreciated. I'm new to XSLT and I have a feeling I'm not using the xsl:for-each construct correctly.
任何帮助表示赞赏。我是XSLT的新手,我觉得我没有正确地使用xsl:for-each结构。
Output I'm getting looks like (just one element ... the first)
输出看起来像(只有一个元素…第一个)
<DisplayText>
SomeData
</DisplayText>
2 个解决方案
#1
3
Sample output not matching what I get
Your sample output does not match mine. You say you're getting:
你的样品产量和我的不一样。你说你得到:
<DisplayText>
SomeData
</DisplayText>
When I run your XSL against your sample input XML, I get this:
当我对您的示例输入XML运行XSL时,我得到以下信息:
<DisplayText/><DisplayText/><DisplayText/><DisplayText/>
I do indeed get one <DisplayText>
element per input <TimeAllocationEntryDetails>
element, as expected. These elements are also empty, as expected.
我确实得到了每个输入一个
Breaking down issues in your code
Your first template is in order:
您的第一个模板是:
<xsl:template match="/TimeSheetDetails">
<xsl:apply-templates select="timeAllocations"/>
</xsl:template>
<TimeSheetDetails>
is indeed the topmost element in the input XML, and this has <timeAllocations>
children.
The next template has some problems:
下一个模板有一些问题:
<xsl:template match="timeAllocations">
<xsl:for-each select="TimeAllocationEntryDetails">
<xsl:for-each select=".">
<DisplayText>
<xsl:value-of select="displayText"/>
</DisplayText>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
One stylistic issue is the use of <xsl:for-each select="TimeAllocationEntryDetails">
here. Since the <timeAllocations>
element has <TimeAllocationEntryDetails>
children, it is more common to use <xsl:apply-templates/>
, optionally specifying select="TimeAllocationEntryDetails"
, and then define a template for handling these elements -- much as you do in your first template.
一个风格上的问题是在这里使用
That aside, you process each <TimeAllocationEntryDetails>
, and then within each one of these, you have another <xsl:for-each select=".">
. This selects .
, which means "the context element" -- which is just the current <TimeAllocationEntryDetails>
again. This second nested for-each
is thus wholly unnecessary.
除此之外,您将处理每个
Within the for-each
structure, you next have:
在for-each结构中,您接下来有:
<DisplayText>
<xsl:value-of select="displayText"/>
</DisplayText>
So for each <TimeAllocationEntryDetails>
element, we create one <DisplayText>
element. We have four <TimeAllocationEntryDetails>
elements in the input XML, and four <DisplayText>
elements in the output XML -- so this works just fine.
因此,对于每个
Within that <DisplayText>
element, you try to get the value of the <displayText>
element that is a child of the <TimeAllocationEntryDetails>
context element. Since no such <displayText>
element exists, this value-of
produces nothing -- so the output <DisplayText>
elements are all empty.
在这个
UPDATE
Your edit changed your input XML. This is what I was responding to:
您的编辑更改了输入XML。这就是我的回答:
<TimesheetDetails>
<timeAllocations>
<TimeAllocationEntryDetails>
.. some child nodes
</TimeAllocationEntryDetails>
<TimeAllocationEntryDetails>
.. some child nodes
</TimeAllocationEntryDetails>
<TimeAllocationEntryDetails>
.. some child nodes
</TimeAllocationEntryDetails>
<TimeAllocationEntryDetails>
.. some child nodes
</TimeAllocationEntryDetails>
</timeAllocations>
</TimesheetDetails>
With your new input XML, the <displayText>
elements now exist, but not at the XPath you're using in <xsl:value-of select="displayText"/>
. This again is looking for the value of the <displayText>
element that is an immediate child of the context element, which in your case would be the <TimeAllocationEntryDetails>
element. Since <displayText>
is not an immediate child, this call to value-of
produces nothing.
使用新的输入XML,
If you want to just output the string value of the entire context XML structure, you could just use <xsl:value-of select="."/>
instead.
如果您只想输出整个上下文XML结构的字符串值,您可以使用
If you want only the value of the <displayText>
element to the exclusion of anything else, either 1) specify the exact XPath to this element, as <xsl:value-of select="activity/displayText"/>
, or 2) use the descendant::
axis, as <xsl:value-of select="descendant::displayText"/>
, or 3) use the //
shorthand for descendant::
, as <xsl:value-of select=".//displayText"/>
(note that you need the .
, or //displayText
equates to the collection of all displayText
elements anywhere in the entire file).
如果您只想要
#2
1
You can simply replace the .
(current node) with a *
(all child elements of the current node) in the second for-each
.
您只需在第二个for-each中使用*(当前节点的所有子元素)替换.(当前节点)。
<xsl:for-each select="TimeAllocationEntryDetails">
<xsl:for-each select="*"> <!-- here -->
...
</xsl:for-each>
</xsl:for-each>
#1
3
Sample output not matching what I get
Your sample output does not match mine. You say you're getting:
你的样品产量和我的不一样。你说你得到:
<DisplayText>
SomeData
</DisplayText>
When I run your XSL against your sample input XML, I get this:
当我对您的示例输入XML运行XSL时,我得到以下信息:
<DisplayText/><DisplayText/><DisplayText/><DisplayText/>
I do indeed get one <DisplayText>
element per input <TimeAllocationEntryDetails>
element, as expected. These elements are also empty, as expected.
我确实得到了每个输入一个
Breaking down issues in your code
Your first template is in order:
您的第一个模板是:
<xsl:template match="/TimeSheetDetails">
<xsl:apply-templates select="timeAllocations"/>
</xsl:template>
<TimeSheetDetails>
is indeed the topmost element in the input XML, and this has <timeAllocations>
children.
The next template has some problems:
下一个模板有一些问题:
<xsl:template match="timeAllocations">
<xsl:for-each select="TimeAllocationEntryDetails">
<xsl:for-each select=".">
<DisplayText>
<xsl:value-of select="displayText"/>
</DisplayText>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
One stylistic issue is the use of <xsl:for-each select="TimeAllocationEntryDetails">
here. Since the <timeAllocations>
element has <TimeAllocationEntryDetails>
children, it is more common to use <xsl:apply-templates/>
, optionally specifying select="TimeAllocationEntryDetails"
, and then define a template for handling these elements -- much as you do in your first template.
一个风格上的问题是在这里使用
That aside, you process each <TimeAllocationEntryDetails>
, and then within each one of these, you have another <xsl:for-each select=".">
. This selects .
, which means "the context element" -- which is just the current <TimeAllocationEntryDetails>
again. This second nested for-each
is thus wholly unnecessary.
除此之外,您将处理每个
Within the for-each
structure, you next have:
在for-each结构中,您接下来有:
<DisplayText>
<xsl:value-of select="displayText"/>
</DisplayText>
So for each <TimeAllocationEntryDetails>
element, we create one <DisplayText>
element. We have four <TimeAllocationEntryDetails>
elements in the input XML, and four <DisplayText>
elements in the output XML -- so this works just fine.
因此,对于每个
Within that <DisplayText>
element, you try to get the value of the <displayText>
element that is a child of the <TimeAllocationEntryDetails>
context element. Since no such <displayText>
element exists, this value-of
produces nothing -- so the output <DisplayText>
elements are all empty.
在这个
UPDATE
Your edit changed your input XML. This is what I was responding to:
您的编辑更改了输入XML。这就是我的回答:
<TimesheetDetails>
<timeAllocations>
<TimeAllocationEntryDetails>
.. some child nodes
</TimeAllocationEntryDetails>
<TimeAllocationEntryDetails>
.. some child nodes
</TimeAllocationEntryDetails>
<TimeAllocationEntryDetails>
.. some child nodes
</TimeAllocationEntryDetails>
<TimeAllocationEntryDetails>
.. some child nodes
</TimeAllocationEntryDetails>
</timeAllocations>
</TimesheetDetails>
With your new input XML, the <displayText>
elements now exist, but not at the XPath you're using in <xsl:value-of select="displayText"/>
. This again is looking for the value of the <displayText>
element that is an immediate child of the context element, which in your case would be the <TimeAllocationEntryDetails>
element. Since <displayText>
is not an immediate child, this call to value-of
produces nothing.
使用新的输入XML,
If you want to just output the string value of the entire context XML structure, you could just use <xsl:value-of select="."/>
instead.
如果您只想输出整个上下文XML结构的字符串值,您可以使用
If you want only the value of the <displayText>
element to the exclusion of anything else, either 1) specify the exact XPath to this element, as <xsl:value-of select="activity/displayText"/>
, or 2) use the descendant::
axis, as <xsl:value-of select="descendant::displayText"/>
, or 3) use the //
shorthand for descendant::
, as <xsl:value-of select=".//displayText"/>
(note that you need the .
, or //displayText
equates to the collection of all displayText
elements anywhere in the entire file).
如果您只想要
#2
1
You can simply replace the .
(current node) with a *
(all child elements of the current node) in the second for-each
.
您只需在第二个for-each中使用*(当前节点的所有子元素)替换.(当前节点)。
<xsl:for-each select="TimeAllocationEntryDetails">
<xsl:for-each select="*"> <!-- here -->
...
</xsl:for-each>
</xsl:for-each>