如何使用 XSLT 复制 XML 以生成相同形式的另一个新 XML

Posted

技术标签:

【中文标题】如何使用 XSLT 复制 XML 以生成相同形式的另一个新 XML【英文标题】:How to copy an XML using XSLT to produce another new XML of the same form 【发布时间】:2018-03-04 18:49:48 【问题描述】:

在使用 XSLT 对 XML 文档执行 3 级排序之后。我无法复制已排序的 xml。我的原始 XML 是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>

    <Test>
    <TestPhase>5</TestPhase>
    <TestFlow>9</TestFlow>
    <TestParameter>5</TestParameter>
    </Test>

    <Test>
    <TestPhase>5</TestPhase>
    <TestFlow>9</TestFlow>
    <TestParameter>2</TestParameter>
    </Test>

    <Test>
    <TestPhase>1</TestPhase>
    <TestFlow>3</TestFlow>
    <TestParameter>1</TestParameter>
    </Test>

    <Test>
    <TestPhase>1</TestPhase>
    <TestFlow>2</TestFlow>
    <TestParameter>2</TestParameter>
    </Test>

    <Test>
    <TestPhase>2</TestPhase>
    <TestFlow>4</TestFlow>
    <TestParameter>6</TestParameter>
    </Test>

    <Test>
    <TestPhase>2</TestPhase>
    <TestFlow>4</TestFlow>
    <TestParameter>1</TestParameter>
    </Test>

    <Test>
    <TestPhase>2</TestPhase>
    <TestFlow>2</TestFlow>
    <TestParameter>10</TestParameter>
    </Test>

    <Test>
    <TestPhase>2</TestPhase>
    <TestFlow>2</TestFlow>
    <TestParameter>1</TestParameter>
    </Test>
    .
    .
    .
    .
    .
    </Root>  

3级排序后,我复制了一份。但新的 XML (test.xml) 似乎如下:

<Test><TestPhase>3</TestPhase><TestFlow>2</TestFlow><TestParameter>1</TestParameter></Test><Test><TestPhase>3</TestPhase><TestFlow>2</TestFlow><TestParameter>2</TestParameter></Test><Test><TestPhase>4</TestPhase><TestFlow>1</TestFlow><TestParameter>1</TestParameter></Test><Test><TestPhase>4</TestPhase><TestFlow>1</TestFlow><TestParameter>2</TestParameter></Test><Test><TestPhase>4</TestPhase><TestFlow>2</TestFlow><TestParameter>1</TestParameter></Test><Test><TestPhase>4</TestPhase><TestFlow>2</TestFlow><TestParameter>2</TestParameter></Test><Test><TestPhase>5</TestPhase><TestFlow>1</TestFlow><TestParameter>1</TestParameter></Test><Test><TestPhase>5</TestPhase><TestFlow>1</TestFlow><TestParameter>2</TestParameter></Test><Test><TestPhase>5</TestPhase><TestFlow>2</TestFlow><TestParameter>1</TestParameter></Test><Test><TestPhase>5</TestPhase><TestFlow>2</TestFlow><TestParameter>2</TestParameter></Test><Test><TestPhase>6</TestPhase><TestFlow>1</TestFlow><TestParameter>1</TestParameter></Test><Test><TestPhase>6</TestPhase><TestFlow>1</TestFlow><TestParameter>2</TestParameter></Test><Test><TestPhase>6</TestPhase><TestFlow>2</TestFlow><TestParameter>1</TestParameter></Test><Test><TestPhase>6</TestPhase><TestFlow>2</TestFlow><TestParameter>2</TestParameter></Test><Test><TestPhase>7</TestPhase><TestFlow>1</TestFlow><TestParameter>1</TestParameter></Test><Test><TestPhase>7</TestPhase><TestFlow>1</TestFlow><TestParameter>2</TestParameter></Test><Test><TestPhase>7</TestPhase><TestFlow>2</TestFlow><TestParameter>1</TestParameter></Test><Test><    .
    .
    .
    .
    .

请在这方面给我建议。我是 XPath / XSLT 的新手。我的 XSLT 是这样写的:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="Root">
    <xsl:apply-templates>
      <xsl:sort select="TestPhase" data-type="number" order="ascending"/>
      <xsl:sort select="TestFlow" data-type="number" order="ascending"/>
      <xsl:sort select="TestParameter" data-type="number" order="ascending"/>
    </xsl:apply-templates>
  </xsl:template>


  <xsl:template match="@* | node()">
    <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

我还检查了我的代码,方法是只复制原始 XML,而不对其进行排序。出现同样的问题。我尝试了以下 XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

这个词:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

虽然我正在使用,但没有出现在第一行

<xsl:output method="xml" indent="yes"/>

尽管我选择了,但一切都崩溃了:

indent="yes"

请帮忙。非常感谢您的帮助。

谢谢。

干杯:)

【问题讨论】:

您实际上是如何执行 XSLT 转换的?您使用的是什么 XSLT 处理器?请注意,缩进(或缺少)实际上并不是由 XSLT 进程本身完成的,而是由将结果序列化为字符串的东西完成的。 【参考方案1】:

首先,您所指的“词”是 xml 声明。要将其包含在您的输出中,您应该将“omit-xml-declaration”添加到 xsl:output 语句(如果您希望将其包含在声明中,请与“standalone”一起)

 <xsl:output method="xml" indent="yes" omit-xml-declaration="no" standalone="yes" />

但是,这最初是行不通的,因为要使输出 XML 文档独立,它必须格式正确,只有一个根元素。您当前匹配 Root 的模板没有复制该元素。

此外,通过执行xsl:apply-templates,您将选择Root 的所有子节点,但这包括空白节点,而不仅仅是Test 元素。要解决这个问题,您可以通过执行&lt;xsl:apply-templates select="Test"&gt; 来明确选择Test 元素。或者,您可以通过将 &lt;xsl:strip-space elements="*" /&gt; 添加到 XSLT 来从 XML 中删除仅空白节点。

试试这个 XSLT,例如:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:output method="xml" indent="yes" omit-xml-declaration="no" standalone="yes" />

  <xsl:template match="Root">
    <xsl:copy>
    <xsl:apply-templates select="Test">
      <xsl:sort select="TestPhase" data-type="number" order="ascending"/>
      <xsl:sort select="TestFlow" data-type="number" order="ascending"/>
      <xsl:sort select="TestParameter" data-type="number" order="ascending"/>
    </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

至于实际结果没有缩进,这取决于转换的结果是如何被序列化的。如果您使用的是 C#(我根据您之前提出的问题做出了这个假设),您可能需要检查是否将 xslt 输出设置传递给 XmlWriter。请参阅https://msdn.microsoft.com/en-us/library/system.xml.xsl.xslcompiledtransform.outputsettings(v=vs.110).aspx,它给出了这个例子:

XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(stylesheet);
XPathDocument doc = new XPathDocument(filename);
XmlWriter writer = XmlWriter.Create(Console.Out, xslt.OutputSettings);
xslt.Transform(doc, writer);
writer.Close();

【讨论】:

非常感谢 Tim C。我终于能够生成带有缩进文档元素和声明的 XML。但是,仍然存在一个小缺陷,尽管我按照您的方法,但没有standalone="yes"。但是,非常感谢来自 newbuntu 的 Tim C. Cheers!

以上是关于如何使用 XSLT 复制 XML 以生成相同形式的另一个新 XML的主要内容,如果未能解决你的问题,请参考以下文章

自动生成XSLT - 通用/默认XSLT

XSLT - 动态添加元素

如何使用 XSLT saxonica 将 xml 转换为点? [复制]

Adobe LiveCycle:使用 XSLT 将 XML 转换为 XML

使用 XSLT 从 XML 生成 EXCEL

基于 XSD 变化的动态 XSLT 生成