XSLT相关标签按属性在同一输出行中

时间:2015-05-23 06:19:21

标签: xslt

尝试进行此转换,但无法在网络或文档中找到答案(此处为newbe)。

试着做这样的事情:

<Info>
        <Type p="1">MyType1</Type>
        <Type p="2">MyType2</Type>
        <Type p="3">MyType3</Type>
        <Values>
            <r p="1">MyValue1</r>
            <r p="2">MyValue2</r>
            <r p="3">MyValue3</r>
        </Values>
</Info>

显示为这样的纯文本转换:

MyType1;MyValue1
MyType2;MyValue3
MyType3;MyValue3

作为输出的两个字段由“p”属性连接¿是否可能?

4 个答案:

答案 0 :(得分:4)

XSLT有a built-in mechanism for handling cross-references;最好使用它:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />

<xsl:key name="value" match="r" use="@p" />

<xsl:template match="/Info">
    <xsl:for-each select="Type">
        <xsl:value-of select="."/>
            <xsl:text>;</xsl:text>
            <xsl:for-each select="key('value', @p)">
                <xsl:value-of select="."/>
                <xsl:if test="position()!= last()">
                    <xsl:text>;</xsl:text>
                </xsl:if>
            </xsl:for-each>     
        <xsl:if test="position()!= last()">
            <xsl:text>&#10;</xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

假设:

  1. 每个Type条目都是唯一的;
  2. 可能有多个具有相同类型的值;例如,以下输入:

    <Info>
    <Type p="1">MyType1</Type>
    <Type p="2">MyType2</Type>
    <Type p="3">MyType3</Type>
    <Values>
        <r p="1">MyValue1</r>
        <r p="2">MyValue2a</r>
        <r p="2">MyValue2b</r>
        <r p="3">MyValue3</r>
    </Values>
    

    将返回:

    MyType1;MyValue1
    MyType2;MyValue2a;MyValue2b
    MyType3;MyValue3
    

答案 1 :(得分:1)

一种可能的解决方案是使用匹配Type的模板打印Type的值,后跟相应r元素的值和匹配Values的空模板避免像这样两次打印Values

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
 <xsl:strip-space elements="*"/>
 <xsl:template match="Type">
 <xsl:variable name="current" select="@p"/>
   <xsl:value-of select="."/>
   <xsl:value-of select="concat(';',//Values/r[@p=$current])"/>
   <xsl:if test="position() != last()">
     <xsl:text>&#xa;</xsl:text>
   </xsl:if>
 </xsl:template>
 <xsl:template match="Values"/>
</xsl:transform>

应用于您的输入,生成以下输出:

MyType1;MyValue1
MyType2;MyValue2
MyType3;MyValue3

答案 2 :(得分:1)

这是一个相当简单的方法

<xsl:template match="/">

  <xsl:variable name="newline">
    <xsl:text>&#xa;</xsl:text>
  </xsl:variable>

  <xsl:for-each select="/Info/Type" >
    <xsl:variable name="p" select="@p" />
    <xsl:value-of select="." />
    <xsl:text>;</xsl:text>
    <xsl:value-of select=" /Info/Values/r[@p=$p] " />
    <xsl:if test=" position() != last() ">
      <xsl:value-of select="$newline" />
    </xsl:if>
  </xsl:for-each>
</xsl:template>

这将为每个Type节点仅选择第一个匹配的Values / r节点。因此,假设应忽略具有相同@p的任何其他值/ r节点。

答案 3 :(得分:1)

使用这个简单而简短的XSLT 1.0解决方案

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kRByP" match="r" use="@p"/>

 <xsl:template match="Type/text()">
  <xsl:value-of select="concat(.,';',key('kRByP', ../@p), '&#xA;')"/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

在提供的源XML文档上应用此转换时

<Info>
    <Type p="1">MyType1</Type>
    <Type p="2">MyType2</Type>
    <Type p="3">MyType3</Type>
    <Values>
        <r p="1">MyValue1</r>
        <r p="2">MyValue2</r>
        <r p="3">MyValue3</r>
    </Values>
</Info>

产生了想要的正确结果

MyType1;MyValue1
MyType2;MyValue2
MyType3;MyValue3

<强>解释

  1. 使用键,模板匹配和XSLT处理模型的工作方式。只有想要的文本节点匹配,其余的被忽略(“删除”)。
  2. 假设p属性的值唯一标识此属性所属的rType元素