Home > Blockchain >  Remove Element from xDocument based on value in repeating segment
Remove Element from xDocument based on value in repeating segment

Time:11-30

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(); 
                }
            }
            
        }
    }
 
}
  • Related