XML排序/格式化工具

时间:2009-09-14 21:31:56

标签: xml formatting

是否有任何工具可以(漂亮地打印)格式化XML文件以及对其元素和属性进行排序?

5 个答案:

答案 0 :(得分:14)

我喜欢这个工具:https://xmlsorter.codeplex.com/

您可以按标签名称和属性进行排序。我喜欢在比较一些XML文件之前使用它。

XML Sorter main window

答案 1 :(得分:8)

我正在寻找一个类似的实用工具并没有真正找到我想要的东西,所以我只是差不多写了一个。它非常简单(并且不包括节点排序中的属性),但有效。

也许它会对其他人有用..它在GitHub上。

这里有一点来自GitHub页面......

USAGE: sortxml.exe [options] infile [outfile]

  infile      The name of the file to sort, etc.
  outfile     The name of the file to save the output to.
              If this is omitted, then the output is written to stdout.

OPTIONS:

  --pretty    Ignores the input formatting and makes the output look nice.
  --sort      Sort both the nodes and attributes.
  --sortnode  Sort the nodes.
  --sortattr  Sort the attributes.

(prefix an option with ! to turn it off.)

默认是输出漂亮且已排序的节点和属性。这是一个例子:

> type sample.xml
<?xml version="1.0" encoding="utf-8" ?><root><node value="one" attr="name"/></root>

> sortxml.exe sample.xml
<?xml version="1.0" encoding="utf-8"?>
<root>
  <node attr="name" value="one" />
</root>

答案 2 :(得分:4)

出于对Visual Studio的沮丧,似乎重新排序&amp;一直重写EDMX文件(实体框架)(另请参阅此Uservoice),我写了一些Linqpad代码来重新排序。然而,在LinqPad之外使用它很容易(也很明显)。

它按元素类型(标签)对元素进行排序,然后按元素属性“名称”的值进行排序,然后通过其他一些东西来尝试使其具有确定性(不同的xml,但含义相同,是[通常]相同的输出 - 见代码)。

它还命令属性。请注意,语义 XML属性可能没有(相关)顺序,但文本,并且版本控制系统仍然认为它们是纯文本...

(请注意,它不会修复Entity Framework edmx file regenerating differently amongst team中提到的不同别名)

void Main()
{
    XDocument xdoc = XDocument.Load(@"\\filepath1\file1.edmx");

    var orderedElements = CopyAndSortElements(xdoc.Elements());

    var newDoc = new XDocument();
    newDoc.Add(orderedElements);
    newDoc.Save(@"\\filepath1\file1.Ordered.edmx");
}

public IEnumerable<XElement> CopyAndSortElements(IEnumerable<XElement> elements)
{
    var newElements = new List<XElement>();
    // Sort XElements by Tag & name-attribute (and some other properties)
    var orderedElements = elements.OrderBy(elem => elem.Name.LocalName) // element-tag
                                  .ThenByDescending(elem => elem.Attributes("Name").Count()) // can be 0, more than 1 is invalid XML
                                  .ThenBy(elem => (elem.Attributes("Name").Any() ? elem.Attributes("Name").First().Value.ToString() : string.Empty))
                                   // in case of no Name-Attributes, try to sort by (number of) children
                                  .ThenBy(elem => elem.Elements().Count())
                                  .ThenBy(elem => elem.Attributes().Count())
                                  // next line may vary for textually different but semantically equal input when elem & attr were unordered on input, but I need to restrain myself...
                                  .ThenBy(elem => elem.ToString());
    foreach (var oldElement in orderedElements)
    {
        var newElement = new XElement(oldElement.Name);
    if (oldElement.HasElements == false && string.IsNullOrEmpty(oldElement.Value) == false)
    {
        // (EDMX does not have textual nodes, but SO-users may use it for other XML-types ;-) )
        // IsNullOrEmpty-check: not setting empty value keeps empty-element tag, setting value (even empty) causes start-tag immediately followed by an end-tag
        // (empty-element tags may be a matter of taste, but for textual comparison it will matter!)
        newElement.Value = oldElement.Value;
    }
        var orderedAttrs = oldElement.Attributes().OrderBy(attr => attr.Name.LocalName).ThenBy(attr => attr.Value.ToString());
        newElement.Add(orderedAttrs);
        newElement.Add(CopyAndSortElements(oldElement.Elements()));
        newElements.Add(newElement);
    }
    return newElements;
}
PS:我们最终使用了XSLT,其他人同时写道。我认为在每个人的构建过程中都更容易/更好。 但也许/希望这对某些人有用。

答案 3 :(得分:3)

我发现这篇帖子:http://www.biglist.com/lists/xsl-list/archives/200106/msg01225.html使用以下XSLT来缩进XML并对属性进行排序:

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

  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="*">
    <xsl:copy>
      <!-- Sort the attributes by name. -->
      <xsl:for-each select="@*">
        <xsl:sort select="name( . )"/>
        <xsl:copy/>
      </xsl:for-each>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="text()|comment()|processing-instruction()">
    <xsl:copy/>
  </xsl:template>

</xsl:stylesheet>

我还没有尝试过,但很可能我会坚持使用XSLT为我做格式化。

答案 4 :(得分:0)

当我试图弄清楚如何排序和edmx文件时,我发现了这篇文章。 我的解决方案基于找到的Arvo Bowens解决方案 https://stackoverflow.com/a/19324438/212241

void Main()
{
    XDocument xdoc = XDocument.Load(@"C:\git\Nvision\Source\NvisionEntities\NvisionModel.edmx");
    Sort(xdoc.Root);
    xdoc.Save(@"C:\git\Nvision\Source\NvisionEntities\NvisionModel.edmx");
}

public void Sort(XElement source, bool bSortAttributes = true)
{
    //Make sure there is a valid source
    if (source == null) throw new ArgumentNullException("source");

    //Sort attributes if needed
    if (bSortAttributes)
    {
        List<XAttribute> sortedAttributes = source.Attributes().OrderBy(a => a.ToString()).ToList();
        sortedAttributes.ForEach(a => a.Remove());
        sortedAttributes.ForEach(a => source.Add(a));
    }

    //Sort the children IF any exist
    List<XElement> sortedChildren = source.Elements().OrderBy(elem => elem.Attributes("Name").Any() ? elem.Attributes("Name").First().Value.ToString() : string.Empty).ToList();
    if (source.HasElements)
    {
        source.RemoveNodes();
        sortedChildren.ForEach(c => Sort(c));
        sortedChildren.ForEach(c => source.Add(c));
    }
}