как удалить дубликаты значений в файле XML и сохранить последние? - PullRequest
2 голосов
/ 15 марта 2012

Мне нужно подавить все повторяющиеся значения в файле XML и сохранить окончательное значение (см. Целевой файл).

Пожалуйста, помогите, так как я не знаю, должен ли я использовать xslt, python или любой .NET API

Вот исходный файл:

<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<cd>
    <artist>Bob Dylan</artist>
</cd>
<cd>
    <title>Hide your heart</title>
</cd>
<cd>
    <title>old_value</title>
    <title>inbetween_value</title>
    <title>new_value</title>
</cd>
</catalog>

Ожидаемый целевой файл:

<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<cd>
    <artist>Bob Dylan</artist>
</cd>
<cd>
    <title>Hide your heart</title>
</cd>
<cd>
    <title>new_value</title>
</cd>
</catalog>

Ответы [ 4 ]

1 голос
/ 15 марта 2012

Существует чрезвычайно простое (без явных условных обозначений, без осей) решение XSLT :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output encoding="ISO-8859-1"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="cd/title[not(position() = last())]"/>
</xsl:stylesheet>

Когда это преобразование применяется к предоставленному документу XML :

<catalog>
    <cd>
        <artist>Bob Dylan</artist>
    </cd>
    <cd>
        <title>Hide your heart</title>
    </cd>
    <cd>
        <title>old_value</title>
        <title>inbetween_value</title>
        <title>new_value</title>
    </cd>
</catalog>

желаемый, правильный результат получается :

<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
   <cd>
      <artist>Bob Dylan</artist>
   </cd>
   <cd>
      <title>Hide your heart</title>
   </cd>
   <cd>
      <title>new_value</title>
   </cd>
</catalog>
1 голос
/ 15 марта 2012

XSLT 1 версия:

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

<xsl:template match="*">
 <xsl:copy>
  <xsl:copy-of select="@*"/>
  <xsl:apply-templates/>
 </xsl:copy>
</xsl:template>
<xsl:template match="cd/*">
 <xsl:if test="not(following-sibling::*[name()=name(current())])">
  <xsl:copy-of select="."/>
 </xsl:if>
</xsl:template>
</xsl:stylesheet>
0 голосов
/ 15 марта 2012

Для удаления всех дубликатов вы можете сохранять контроль между именами тегов и элементами.В Python с минидомом:

xml = """<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<cd>
  <artist>Bob Dylan</artist>
</cd>
<cd>
  <title>Hide your heart</title>
</cd>
<cd>
  <artist>Bob Dylan</artist>
  <title>old_value</title>
  <title>inbetween_value</title>
  <title>new_value</title>
  <artist>Freddie Mercury</artist>
  <title>Don't stop me now</title>
</cd>
</catalog>"""

from xml.dom import minidom
doc = minidom.parseString(xml)

for cd in doc.getElementsByTagName("cd"):
  elements = {}
  for element in cd.childNodes:
    if element.nodeType is not minidom.Node.ELEMENT_NODE:
      continue
    if element.tagName in elements:
      cd.removeChild(element)
      print("Removed duplicated " + element.tagName)
    elements[element.tagName] = element

# doc.writexml(open("/path/to/file", "w"))
0 голосов
/ 15 марта 2012

Вы можете использовать любую технологию, какую захотите.Если ваше требование: «Для каждого элемента cd оставьте только последнее значение для дубликатов имен дочерних элементов», вот решение LINQ to XML, если у вас есть XDocument с именем oldDoc:

var scrubbedDoc = new XDocument(new XElement("catalog",
    from cd in oldDoc.Element("catalog").Elements("cd")
    select new XElement("cd",
        from elementsGroupedByName in cd.Elements().ToLookup(e => e.Name)
        select elementsGroupedByName.Last())));
...