Xml 尝试选择第一个匹配元素时XSLT出现意外行为
我有一些数据要以特定格式序列化为XML。我有一个Xml 尝试选择第一个匹配元素时XSLT出现意外行为,xml,xslt,Xml,Xslt,我有一些数据要以特定格式序列化为XML。我有一个TestClass数组,它由两个字符串属性组成:A和B 我知道这听起来不是一个好的做法,但在本例中,我希望A的值对于TestClass的所有实例都是相同的 我想创建一个包含公共A值和所有B值的XML文件。我编写了以下代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serializati
TestClass
数组,它由两个字符串属性组成:A
和B
我知道这听起来不是一个好的做法,但在本例中,我希望A
的值对于TestClass
的所有实例都是相同的
我想创建一个包含公共A
值和所有B
值的XML文件。我编写了以下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Xml.Xsl;
using System.IO;
namespace test
{
public class Program
{
public class TestClass
{
public string A { get; set; }
public string B { get; set; }
}
static void Main(string[] args)
{
TestClass[] array = new TestClass[]
{
new TestClass() { A = "A1", B="B1"},
new TestClass() { A = "A2", B="B2"}
};
XmlSerializer serializer = new XmlSerializer(typeof(TestClass[]));
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load("test.xslt");
string xml1Name = @"c:\temp\xmltest\original.xml";
string xml2Name = @"c:\temp\xmltest\transformed.xml";
using (FileStream xmlStream = new FileStream(xml1Name, FileMode.Create))
{
serializer.Serialize(xmlStream, array);
}
xslt.Transform(xml1Name, xml2Name);
}
}
}
test.xslt包含以下内容:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:template match="/ArrayOfTestClass/TestClass[1]">
<Test>
<A>
<xsl:value-of select="A"/>
</A>
<B_Values>
<xsl:for-each select="/ArrayOfTestClass/TestClass">
<value>
<xsl:value-of select="B" />
</value>
</xsl:for-each>
</B_Values>
</Test>
</xsl:template>
</xsl:stylesheet>
为什么我的XSLT不能生成我期望的结果?如何使其正确?这是因为XSLT的特性,在XSLT处理器无法在样式表中找到它试图匹配的节点的特定模板的情况下使用XSLT。元素和根节点的内置模板本质上是跳过元素并查找与其子元素匹配的模板。如果找到文本节点,它将输出文本
在XSLT中,没有与/
或ArrayOfTestClass
元素匹配的模板,因此内置模板将生效。如果是ArrayOfTestClass
的情况,它将查找与其所有子节点匹配的模板,但您只有一个与第一个子节点匹配的特定模板。因此,其他TestClass
元素将由内置模板匹配,最终输出其中的文本
您只需添加一个模板,告诉XSLT停止处理其他TestClass
元素。您可以添加此模板
<xsl:template match="/ArrayOfTestClass/TestClass[position() > 1]" />
这利用了这样一个事实,即当多个模板可能匹配同一元素时,XSLT将优先考虑更具体的模板。这是因为XSLT的重要性,在XSLT处理程序无法在其试图匹配的节点的样式表中找到特定模板的情况下使用XSLT。元素和根节点的内置模板本质上是跳过元素并查找与其子元素匹配的模板。如果找到文本节点,它将输出文本
在XSLT中,没有与/
或ArrayOfTestClass
元素匹配的模板,因此内置模板将生效。如果是ArrayOfTestClass
的情况,它将查找与其所有子节点匹配的模板,但您只有一个与第一个子节点匹配的特定模板。因此,其他TestClass
元素将由内置模板匹配,最终输出其中的文本
您只需添加一个模板,告诉XSLT停止处理其他TestClass
元素。您可以添加此模板
<xsl:template match="/ArrayOfTestClass/TestClass[position() > 1]" />
这利用了一个事实,即当多个模板可能匹配同一元素时,XSLT将优先考虑更具体的模板。谢谢。这正是我需要的。谢谢。这正是我需要的。
<xsl:template match="/ArrayOfTestClass/TestClass[position() > 1]" />
<xsl:template match="TestClass" />