In the XML below I am trying to remove the /Bundle/entry/resource/Patient/contained/Patient elements when any of the /Bundle/entry/resource/Patient/contained/Patient/identifier/system value attributes contain "remove-this-Patient" , I could use the full value == "https://example.com/remove-this-Patient" but the "contain" is better for me since the url section can be from multiple places and be slightly different.
I have tried the two code samples below and other variations but none work. The code runs without error but the target Patient element is not removed.
Just as a test I tried using the /Bundle/entry/resource/Patient/contained/Patient/id element in the "where" clause and I was able to get this to work, so I think it has something to do with the /Bundle/entry/resource/Patient/contained/Patient/identifier element being repeating inside the Patient element.
Starting XML
<Bundle>
<id value="xxxx" />
<entry>
<fullUrl value="xxxxxxx" />
<resource>
<Patient>
<id value="xxxx" />
<contained>
<Practitioner>
<id value="xx"/>
</Practitioner>
</contained>
<contained>
<Patient>
<id value="xxxx" />
<identifier>
<type>
<coding>
</coding>
</type>
<system value="http://example.com/remove-this-Patient" />
<value value="xxx" />
</identifier>
<identifier>
<type>
<coding>
</coding>
</type>
<system value="https://example.com/some-other-value" />
<value value="xxx" />
</identifier>
</Patient>
</contained>
<contained>
<Patient>
<id value="xxxx" />
<identifier>
<type>
<coding>
</coding>
</type>
<system value="https://example.com/some-other-thing" />
<value value="xxx" />
</identifier>
<identifier>
<type>
<coding>
</coding>
</type>
<system value="https://example.com/some-other-value" />
<value value="xxx" />
</identifier>
</Patient>
</contained>
</Patient>
</resource>
</entry>
</Bundle>
Desired output would have the /contained/Patient element removed when the child element identifier/system value = "http://example.com/remove-this-Patient"
<Bundle>
<id value="xxxx" />
<entry>
<fullUrl value="xxxxxxx" />
<resource>
<Patient>
<id value="xxxx" />
<contained>
<Practitioner>
<id value="xx"/>
</Practitioner>
</contained>
<contained>
</contained>
<contained>
<Patient>
<id value="xxxx" />
<identifier>
<type>
<coding>
</coding>
</type>
<system value="https://example.com/some-other-thing" />
<value value="xxx" />
</identifier>
<identifier>
<type>
<coding>
</coding>
</type>
<system value="https://example.com/some-other-value" />
<value value="xxx" />
</identifier>
</Patient>
</contained>
</Patient>
</resource>
</entry>
</Bundle>
The two queries below are my attempt to make it work with XDocument, but neither work. They run without error but do not remove the Patient.
xdoc.Root.Descendants("entry").Descendants("resource").Descendants("Patient").Descendants("contained").Descendants("Patient").Where(x => x.Element("identifier").Element("system").Attribute("value").Value.Contains("remove-this-Patient")).Remove();
xdoc.Root.Descendants("entry").Descendants("resource").Descendants("Patient").Descendants("contained").Descendants("Patient").Where(x => (string)x.Descendants("identifier").Where(y=> ("system").Attribute("value")=="https://example.com/remove-this-Patient").Remove();
CodePudding user response:
Please try the following solution based on XSLT transformation.
The XSLT below is following a so called Identity Transform pattern.
The 2nd template removes not needed "/Bundle/entry/resource/Patient/contained/Patient" XML elements based on the presence of the 'remove-this-Patient' value in the @value attribute.
Input XML
<Bundle>
<id value="xxxx"/>
<entry>
<fullUrl value="xxxxxxx"/>
<resource>
<Patient>
<id value="xxxx"/>
<contained>
<Practitioner>
<id value="xx"/>
</Practitioner>
</contained>
<contained>
<Patient>
<id value="xxxx"/>
<identifier>
<type>
<coding>
</coding>
</type>
<system value="http://example.com/remove-this-Patient"/>
<value value="xxx"/>
</identifier>
<identifier>
<type>
<coding>
</coding>
</type>
<system value="https://example.com/some-other-value"/>
<value value="xxx"/>
</identifier>
</Patient>
</contained>
<contained>
<Patient>
<id value="xxxx"/>
<identifier>
<type>
<coding>
</coding>
</type>
<system value="https://example.com/some-other-thing"/>
<value value="xxx"/>
</identifier>
<identifier>
<type>
<coding>
</coding>
</type>
<system value="https://example.com/some-other-value"/>
<value value="xxx"/>
</identifier>
</Patient>
</contained>
</Patient>
</resource>
</entry>
</Bundle>
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/Bundle/entry/resource/Patient/contained/Patient[identifier/system[contains(@value, 'remove-this-Patient')]]">
</xsl:template>
</xsl:stylesheet>
Output XML
<Bundle>
<id value="xxxx" />
<entry>
<fullUrl value="xxxxxxx" />
<resource>
<Patient>
<id value="xxxx" />
<contained>
<Practitioner>
<id value="xx" />
</Practitioner>
</contained>
<contained />
<contained>
<Patient>
<id value="xxxx" />
<identifier>
<type>
<coding />
</type>
<system value="https://example.com/some-other-thing" />
<value value="xxx" />
</identifier>
<identifier>
<type>
<coding />
</type>
<system value="https://example.com/some-other-value" />
<value value="xxx" />
</identifier>
</Patient>
</contained>
</Patient>
</resource>
</entry>
</Bundle>
CodePudding user response:
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication5
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
string id = "xxxx";
List<XElement> possibleDeletes = doc.Descendants().Where(x => (x.Element("identifier") != null) && (string)x.Element("id").Attribute("value") == id).ToList();
foreach (XElement possibleDelete in possibleDeletes)
{
List<XElement> identifiers = possibleDelete.Elements("identifier").ToList();
foreach (XElement identifier in identifiers)
{
if (((string)identifier.Element("system").Attribute("value")).Contains("remove")) identifier.Remove();
}
}
}
}
}