0

我有想要以特定格式序列化为 XML 的数据。我有一个数组TestClass,它由两个字符串属性组成:AB

我知道这听起来不像是好的做法,但在这种情况下,我希望 . 的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>

我希望我的代码应该输出两个文件。XMLSerializer 类生成的“默认”序列化似乎是正确的。

<?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>

XSLT 转换的 XML 几乎是正确的,但它包含一些额外的尾随文本,这似乎是序列化数组的第二个元素的值A和中的值。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

为什么我的 XSLT 没有生成我期望的结果?我怎样才能使它正确?

4

1 回答 1

3

这是因为 XSLT 的内置模板在 XSLT 处理器无法在样式表中为它试图匹配的节点找到特定模板的情况下使用。元素和根节点的内置模板本质上是跳过元素并寻找与其子元素匹配的模板。如果它找到一个文本节点,它将输出文本。

在您的 XSLT 中,您没有与其中一个/ArrayOfTestClass元素匹配的模板,因此内置模板启动。如果它的情况下ArrayOfTestClass会寻找与其所有子节点匹配的模板,但您只有一个与第一个子节点匹配的特定模板。因此其他TestClass元素将被内置模板匹配,并最终输出其中的文本。

您需要做的就是添加一个模板来告诉 XSLT 停止处理其他TestClass元素。你可以添加这个模板

<xsl:template match="/ArrayOfTestClass/TestClass[position() > 1]" />

但是,如果您只想将TestClass元素作为元素的子节点ArrayOfTestClass,则可以将其简化为

<xsl:template match="TestClass" />

这利用了当多个模板可能匹配同一个元素时,XSLT 将优先考虑更具体的模板这一事实。

于 2013-08-28T22:21:43.770 回答