• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Parsing XML with Namespaces

Participant ,
May 15, 2023 May 15, 2023

Copy link to clipboard

Copied

I am trying to use javascript to read an XML file with a custom namespace and feed the contents of several nodes into a series of javascriopt variables.

I have gone through numerous posts in this forum and others (see list below), but have not found an answer that works, doesn't contain a reference link to as dead url, or that I can understand (I am pretty new to js).

 

That said, I am clearly not the first to struggle with this issue.

 

Some of the specific posts I have looked at include:

 

So far, I have not been able to get anything to work!

 

The top of my XML looks like this:

 

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="../CO-Medicare_Combined-Structure.xsd"?>
<!DOCTYPE Root [
  <!ENTITY path "file:///C:/Users/O146962/OneDrive - Kaiser Permanente/Desktop/Indesign Automation POC/Assets/Icons/">
]>
<Root xmlns="kpPDCommon" xmlns:kpdc="kpPDCommon">
  <region kpdc:regionCD="CO">CO</region>
  <lob kpdc:lobCD="MCAR">Medicare</lob>
  <serviceArea>Denver Boulder</serviceArea>
  <planName>Senior Advantage Medicare Medicaid</planName>

 

I am trying to get the contents of "region", "lob", "serviceArea", and "planName" and use that to popluate js variables. However, even just trying to check to see if the file contains "Root" comes back as "Undefined"!

Here is my current javascript&colon;

 

#include "glue code.jsx";

var mainFolder = Folder.desktop + "/Indesign Automation POC";
var templateFolder = mainFolder + "/Template Files - CO";
var outputFolder = mainFolder + "/ID_ScriptOutput";

var dataPath = mainFolder + "/Data/CO_DNB-XML_TEST_SPLIT";
//var file = File(dataPath + "/CO_DNB_Details.xml");
var file = dataPath + '/CO_DNB_Providers_Test_1.xml';

var nskpdc = new Namespace ("kpdc", "kpPDCommon");


var xmlFile = new XML(file);
//xmlFile.addNamespace(nskpdc);
//var nspc = xmlFile.contains("kpdc:Root");


var nspc = xmlFile.contains("Root");

var RGN = xmlFile.elements("region")[0];
var LOB = xmlFile.elements("lob")[0];
var SVCA = xmlFile.elements("serviceArea")[0];
var SVCA_PN = xmlFile.elements("planName")[0];

alert(nspc)
//alert('RGN: ' + RGN + ', LOB: ' + LOB + ', SVCA: ' + SVCA + ', Plan: ' + SVCA_PN);

 

 

I have tried declaring file as a File. I have tried using XML(file.read()). I have tried declaring my namespace. However I am obviously not doing any of this correctly or it should work. 😅

 

Appreciate any help!

 

TOPICS
How to , Scripting , SDK

Views

1.9K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

People's Champ , May 15, 2023 May 15, 2023
var f = File (Folder.desktop+"/test.xml");
f.encoding ="UTF-8";
f.open("r");
var x = XML(f.read());
f.close();
alert(x.xpath("//kpdc:serviceArea"));

Votes

Translate

Translate
People's Champ ,
May 15, 2023 May 15, 2023

Copy link to clipboard

Copied

var f = File (Folder.desktop+"/test.xml");
f.encoding ="UTF-8";
f.open("r");
var x = XML(f.read());
f.close();
alert(x.xpath("//kpdc:serviceArea"));

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
May 15, 2023 May 15, 2023

Copy link to clipboard

Copied

@Loic.Aigon That worked! What a simple solution for something I had som much trouble with. For my edification, what is the "r" for under "open"?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
May 16, 2023 May 16, 2023

Copy link to clipboard

Copied

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
May 16, 2023 May 16, 2023

Copy link to clipboard

Copied

Thank you!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
May 16, 2023 May 16, 2023

Copy link to clipboard

Copied

Something worth mentioning is that as it's E4X related, note that 

x.xpath("//kpdc:serviceArea")

May not return a String object but XML object. 

What I mean here is that if you run a method to the String Object Prototype right away, it may fail.

So you may need to check node type and if xml, call XML method text() to get the String out of the object.

It's likely ExtendScript (as Javascript by nature) will force conversion from type xml to type String but just don't presume using XPath on XML object will return a string even if it looks so.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
May 16, 2023 May 16, 2023

Copy link to clipboard

Copied

Good to know! Much appreciated!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
May 18, 2023 May 18, 2023

Copy link to clipboard

Copied

@Loic.Aigon How would I adjust this if I wanted to load a set of sub-elements into an array?

<saCounties>
        <county>Adams</county>
        <county>Arapahoe</county>
        <county>Boulder</county>
        <county>Broomfield</county>
        <county>Clear Creek</county>
        <county>Denver</county>
        <county>Douglas</county>
        <county>Elbert</county>
        <county>Gilpin</county>
        <county>Jefferson</county>
        <county>Park</county>
    </saCounties>

I want to create an arrary where each "county" element is an item in the array.

let counties = []

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
May 18, 2023 May 18, 2023

Copy link to clipboard

Copied

Well, you can use this expression (to be adjusted with namespaces if any)

var x = <saCounties>
        <county>Adams</county>
        <county>Arapahoe</county>
        <county>Boulder</county>
        <county>Broomfield</county>
        <county>Clear Creek</county>
        <county>Denver</county>
        <county>Douglas</county>
        <county>Elbert</county>
        <county>Gilpin</county>
        <county>Jefferson</county>
        <county>Park</county>
    </saCounties>

var counties = x..county //or x.xpath("/saCounties/county";
//BEWARE counties is NOT a js ARRAY but a XMLList object that can be looped through as arrays but don't get the same methods.
var n = counties.length;
var arrCounties = [];
while(n--) arrCounties[n] = counties[n].text(); //getting string value of node and push it into js array
alert("Counties are:\r"+arrCounties.join(", "));

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
May 18, 2023 May 18, 2023

Copy link to clipboard

Copied

@Loic.Aigon  Tried the folowing (and several variations), but no luck so far. 

 

 

 

const xmlFiles = dataFolder.getFiles("*DirProp.xml");
var f = File(xmlFiles[0]);


f.encoding ="UTF-8";
f.open("r");
var x = XML(f.read());
f.close();

//SAC stands for "Service Area Counties"
const SAC = x.xpath("//kpdc:county");
//BEWARE counties is NOT a js ARRAY but a XMLList object that can be looped through as arrays but don't get the same methods.
alert(SAC)
var n = SAC.length;
var arrCounties = [];
while(n--) arrCounties[n] = SAC[n].text(); //getting string value of node and push it into js array
alert("Counties are:\r"+arrCounties.join(", "));

 

 

 

 

The script runs and the following is returned for SAC:

BenRossKP_0-1684431067703.png

But nothing is returned for:

 

 

 

alert("Counties are:\r"+arrCounties.join(", "));

 

 

 

I just get:

BenRossKP_1-1684431119888.png

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
May 18, 2023 May 18, 2023

Copy link to clipboard

Copied

My bad, length should be length() when used on XMLList Objects:

 

var f = File (Folder.desktop+"/test.xml");
f.encoding ="UTF-8";
f.open("r");
var x = XML(f.read());
f.close();
var counties = x.xpath("//kpdc:county");
var n = counties.length();
var arrCounties = [];
while(n--){
    arrCounties[n] = counties[n].text();
}

alert("Counties are:\r"+arrCounties.join(", "));

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
May 18, 2023 May 18, 2023

Copy link to clipboard

Copied

That worked! Thanks @Loic.Aigon 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
May 31, 2023 May 31, 2023

Copy link to clipboard

Copied

@Loic.Aigon If I needed to create lists from an XML node's child elements, how would I need to adjust your script?

For the following structure:

 <serviceAreaSnippets>
        <svca_db>
            <db_s1><![CDATA[You can go to all the providers on this list, but your costs for some providers may be less for those who offer preferred cost-sharing. We have noted these providers in the listing as “Preferred cost-sharing providers” to distinguish them from other providers in our network that offer standard cost-sharing. Please refer to the Evidence of Coverage for more information.]]></db_s1>
        </svca_db>
        <svca_nco>
            <nco_s1><![CDATA[You can go to all the providers on this list, but your costs for some providers may be less for those who offer preferred cost-sharing. We have noted these providers in the listing as “Preferred cost-sharing providers” to distinguish them from other providers in our network that offer standard cost-sharing. Please refer to the Evidence of Coverage for more information.]]></nco_s1>
            <nco_s1><![CDATA[You can go to all the providers on this list, but your costs for some providers may be less for those who offer preferred cost-sharing. We have noted these providers in the listing as “Preferred cost-sharing providers” to distinguish them from other providers in our network that offer standard cost-sharing. Please refer to the Evidence of Coverage for more information.]]></nco_s1>
        </svca_nco>
        <scva_soco>
            <soco_s1><![CDATA[You can go to all the providers on this list, but your costs for some providers may be less for those who offer preferred cost-sharing. We have noted these providers in the listing as “Preferred cost-sharing providers” to distinguish them from other providers in our network that offer standard cost-sharing. Please refer to the Evidence of Coverage for more information.]]></soco_s1>
            <soco_s2><![CDATA[Senior Advantage Medicare Medicaid Pueblo (HMO D-SNP) plan members: You may only see PCPs who are located in our Kaiser Permanente Medical Offices. Please refer to the listing of these available network providers on pages <8 and 9> of this Provider Directory.]]></soco_s2>
            <soco_s3><![CDATA[Senior Advantage Core, Enhanced and Employer Group (HMO) and (HMO-POS) plan members: You may see any PCP in our network. Please refer to the listing of these available network providers on pages <10 – 51> of this Provider Directory.]]></soco_s3>
            <soco_s4><![CDATA[Senior Advantage Medicare Medicaid Pueblo (HMO D-SNP) plan members: You may only see primary care providers who are located in our Kaiser Permanente Medical Offices. Please refer to the listing of these available network providers on pages <8 and 9> of this Provider Directory.]]></soco_s4>
            <soco_s5><![CDATA[Senior Advantage Core, Enhanced and Employer Group (HMO) and (HMO-POS) plan members: You may see any primary care provider in our network. Please refer to the listing of these available network providers on <pages 10 – 51> of this Provider Directory.]]></soco_s5>
            <soco_s6><![CDATA[All Southern Colorado Senior Advantage Core, Enhanced and Employer Group (HMO) and (HMO-POS) plan members may see any specialty care provider in our network. Please refer to the listing of these available specialty care network providers beginning on page <52> of this Provider Directory.]]></soco_s6>
        </scva_soco>
    </serviceAreaSnippets>

I need to create a separate are for each child of serviceAreaSnippets. So, separate arrays for svca_db, svca_noco, and svca_soco, where each array contains that node's children.

The result would be three arrays:

svca_db [ db_s1's content ]

svca_noco [nco_s1's content, nco_s2's content]

svca_soco [soco_s1's content, ... soco_s6's content]

 

Any idea how to do that?

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Jun 01, 2023 Jun 01, 2023

Copy link to clipboard

Copied

By now, you should start to get the logic:

 function getChildrenText(xParent){

        var arr = [];
        if(!/^(undefined|xml)$/.test(typeof xParent)) return [];
        var c = xParent.children();
        var n = c.length();
        while(n--) arr[n] = c[n].text();
        return arr;
    }

    var svca_db = getChildrenText(x.svca_db);
    var svca_nco = getChildrenText(x.svca_nco);
    var scva_soco = getChildrenText(x.scva_soco);

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jun 01, 2023 Jun 01, 2023

Copy link to clipboard

Copied

Nice! Thanks @Loic.Aigon ! It seems I left out part of my explination though. I am hoping to dynamically name the arrays based on the XML node name. Is that possible?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Jun 01, 2023 Jun 01, 2023

Copy link to clipboard

Copied

Not sure why you would want to have such dynamically names variables but still:

 

function getChildrenText(xParent){

        var arr = [];
        if(!/^(undefined|xml)$/.test(typeof xParent)) return [];
        var c = xParent.children();
        var n = c.length();
        while(n--) arr[n] = c[n].text();
        return arr;
    }

    var c = x.children();
    var n = c.length();
    var xParent;
    while(n--){
        xParent = c[n];
        $.global[xParent.name()]=getChildrenText(xParent);
    }
    alert(svca_db)

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jun 01, 2023 Jun 01, 2023

Copy link to clipboard

Copied

@Loic.Aigon Amazing! Thank you! This is a part of a script that dynamically builds provider print directories for multiple regions across the US. This snippet specfically handles region-specific text content that needs to be inserted at various points throughout the directory. 

 

I'll let you know how it goes!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jun 01, 2023 Jun 01, 2023

Copy link to clipboard

Copied

@Loic.Aigon Where is "x" defined in this script?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jun 01, 2023 Jun 01, 2023

Copy link to clipboard

Copied

Specifically:

var c = x.children();

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jun 01, 2023 Jun 01, 2023

Copy link to clipboard

Copied

@Loic.Aigon  Thank you for being patient with me! I am still learning JS!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jun 01, 2023 Jun 01, 2023

Copy link to clipboard

Copied

@Loic.Aigon Given my XML above and your script, I have:

 

const SVCAS_raw = dpr.xpath("//kpdc:serviceAreaSnippets");
function getChildrenText(xParent){

        var arr = [];
        if(!/^(undefined|xml)$/.test(typeof xParent)) return [];
        var c = xParent.children();
        var n = c.length();
        while(n--) arr[n] = c[n].text();
        return arr;
    }

    var c = x.children();
    var n = c.length();
    var xParent;
    while(n--){
        xParent = c[n];
        $.global[xParent.name()]=getChildrenText(xParent);
    }
 getChildrenText(SVCAS_raw);
 alert(svca_db)

Running this tells me that "x" is undefined.

What am I missing?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jun 01, 2023 Jun 01, 2023

Copy link to clipboard

Copied

@Loic.Aigon BTW, the contents and child nodes of "serviceAreaSnippets" will be different for each region. So Colorado has svca_db, etc. but washington might have svca_seattle.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Jun 01, 2023 Jun 01, 2023

Copy link to clipboard

Copied

x is a variable that needs to host your xml object (as demonstrated before=>var x = XML(xmlFileReference.read())

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jun 02, 2023 Jun 02, 2023

Copy link to clipboard

Copied

Thanks @Loic.Aigon.

It took a little adjusting, but I got it to work!

const dpXML = dataFolder.getFiles("*" + dp_d + ".xml");
dpf = File(dpXML[0]);
dpf.encoding = "UTF-8";
dpf.open("r");
dpr = new XML(dpf.read());
dpf.close();

const SVCAS_raw = dpr.xpath("//kpdc:serviceAreaSnippets").elements();

function getChildrenText(xParent){

        var arr = [];
        if(!/^(undefined|xml)$/.test(typeof xParent)) return [];
        var c = xParent.descendants();
        var n = c.length();
        while(n--) arr[n] = c[n].text();
        return arr;
    }

    var c = SVCAS_raw;
    var n = c.length();
    var xParent;
    while(n--){
        xParent = c[n];
        $.global[xParent.localName()]=getChildrenText(xParent);
        alert(xParent.localName())
    }

alert(svca_soco);

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Jun 03, 2023 Jun 03, 2023

Copy link to clipboard

Copied

On a second thought, adding variables as global ones may not be the greatest idea. Would be better to have an object that you would enrich with properties. Those that you can either loop through or evaluate later.

 

var data  = {

}

 

data

 

var data = {};
var c = SVCAS_raw;
    var n = c.length();
    var xParent;
    while(n--){
        xParent = c[n];
        data[xParent.localName()]=getChildrenText(xParent);
    }
//looping through data
for (prop in data){
var arr = data[prop];
}

//evaluate prop
if (typeof data.svca_db === "undefined") alert("invalid data");

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines