我想要以特定格式序列化为XML的数据。我有一个TestClass
数组,其中包含两个字符串属性:A
和B
。
我知道这听起来不太好,但在这种情况下,我希望A
的所有TestClass
实例的A
值都相同。
我想创建一个包含公共B
值和所有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);
}
}
}
值的XML文件。我写了以下代码:
<?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>
test.xslt包含以下内容:
<?xml version="1.0"?>
<ArrayOfTestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<TestClass>
<A>A1</A>
<B>B1</B>
</TestClass>
<TestClass>
<A>A2</A>
<B>B2</B>
</TestClass>
</ArrayOfTestClass>
我希望我的代码输出两个文件。 XMLSerializer类生成的“默认”序列化似乎是正确的。
A
XSLT转换的XML几乎是正确的,但它包含一些额外的尾随文本,它们在序列化数组的第二个元素中显示为B
和<?xml version="1.0" encoding="utf-8"?>
<Test><A>A1</A><B_Values><value>B1</value><value>B2</value></B_Values></Test>
A2
B2
的值。这不是一个错字:
{{1}}
为什么我的XSLT没有产生我期望的结果?我怎样才能做对吗?
答案 0 :(得分:3)
这是因为XSLT的built-in templates,它用于XSLT处理器无法在样式表中找到它试图匹配的节点的特定模板的情况。元素和根节点的内置模板实质上是跳过元素并查找与其匹配的模板。如果找到文本节点,它将输出文本。
在您的XSLT中,您没有匹配/
或ArrayOfTestClass
元素的模板,因此内置模板会启动。如果ArrayOfTestClass
的情况,它将查找与其所有子节点匹配的模板,但您只有与第一个子节点匹配的特定模板。因此,其他TestClass
元素将与内置模板匹配,最终输出其中的文本。
您需要做的就是添加一个模板,告诉XSLT停止处理其他TestClass
元素。你可以添加这个模板
<xsl:template match="/ArrayOfTestClass/TestClass[position() > 1]" />
但是,如果您只将TestClass
元素作为ArrayOfTestClass
元素的子节点,则可以将其简化为
<xsl:template match="TestClass" />
这利用了当多个模板可能匹配相同元素时,XSLT将优先考虑更具体的模板。