How do I use an XPath conditional expression to replace node text?

I am trying to create an XPath 2.0 expression that will navigate to an attribute, test its value, e.g. "S" or "Sensitive" then replace the text with other text in the attribute's parent.

Using XSLT 2.0 is not an option as I am accepting an XSD compliant document then evaluating node values using XPath expressions stored in a "rules" table, for the document's acceptance or rejection.  The latest wrinkle is not testing for a value in one node attribute, then replacing ALL the text in the node.

The help given will cause me to burn a sacrifice in your names to the BBQ gods (I have not had a great deal of time off lately), and award the assigned points with enthusiasm.

Your expertise is most appreciated.

Thanks you
LVL 1
dcfreyerAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Geert BormansInformation ArchitectCommented:
I am not sure I understand what you want.
XPath can't "replace" in a source XML, it can only address a location or return a value,
so can you tell a little bit about how you execute the XPath?

/element/element[matches(@attribute, '^S(ensitive)')]
will get you the element that has this particular attribute
0
dcfreyerAuthor Commented:
For a received Schema based XML document, I call a procedure that traverses a ruleset table filled with XPath expressions that if validate to true for values found within elements or attributes, the document is placed in a failed_rules table.  The ruleset table is built using an unstructured xml document which is  structured as:

<ruleset name="DocClassifications">
  <rule name = "Document cannot contain SENSITIVE remarks">
       /document/person/remark/code = 'S'
  </rule>
   ...
</ruleset>

What is necessary is use a conditional expression (if-then-else) that will check the attribute "code" for the value "S".  If true then REPLACE the string in the element "remark" with another string - "Not available for this network."

Finding the value of an element or attribute is not a problem.  Performing string manipulation (without XSLT) is.  

What may be a solution is to CALL an external procedure to do the string replacement, but this is not preferred.  I would like to handle it in a regex.

Can you help?
0
Geert BormansInformation ArchitectCommented:
I think the problem is changing the "remark" element using XPath alone would be the problem

Your ruleset seems to have functionality as in schematron,
with a difference that you want the rules to alter the source document

I still don't know how you execute all the XPath expressions
and what "call an external procedure" means in your situation

I also don't see where you have in your ruleset the indication that when true, you need to replace what with what,
so that leaves some issues still vague to me

I have a feeling that I would solve this problem by having an XSLT interprete the ruleset and generate an XSLT that does what your ruleset specifies... so that might be an approach: generate the XSLT to do the replacement action automatically from the ruleset
0
The Ultimate Tool Kit for Technolgy Solution Provi

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy for valuable how-to assets including sample agreements, checklists, flowcharts, and more!

dcfreyerAuthor Commented:
The call to an external to do string manipulation is an option I have not fully investigated, and would prefer not to.
What about creating a regular expression, e.g.,:
                                  if(contains(@<<XPATH to attibute value>>,'<<value>>')
                                  then   replace(@<<XPATH to element containing string>>,$_,'Not Available')
                                  else <<do nothing>>))                                    
I have not don regular expressions usng XPATH and its functions on XML documents - databases OK, XML I have issues.

Thank you for your interest and professionalism.                                
Here is the execution code to evaluate xpath rules against an xml document
 
--Validate document against the rules
PROCEDURE validate_rules (meta_doc  IN xmldom.DOMDocument,
                                        ruleset_name    IN      VARCHAR2,
                                        valid                 OUT  BOOLEAN,
                                        errors                OUT  VARCHAR2
                                        ) IS
     errcount      NUMBER    := 0;
     rulesetId     NUMBER    := idForRuleSet(ruleset_name);
BEGIN
     IF xmldom.isNull(meta_doc) THEN
         valid := FALSE;
         errors := Cannot validate.  Document is null;
     ELSIF rulesetId IS NULL THEN
         valid := FALSE;
         errors := Cannot validate. Ruleset ||ruleset_name|| does not                                                     exist.;
ELSE
   --Assume the document is valid until proven otherwise.
   valid := TRUE;
   --Loop over all the rules for the ruleset whose name is passed in
FOR curRule IN (SELECT name, xpath_test FROM rules_t WHERE ruleset = rulesetId)
 
LOOP
   --call xpath_h.test on the current rules expression
  IF NOT xpath_h.test(meta_doc, curRule.xpath_h_test) THEN
     --keep track of all the rules that fail by bumping the error count
     errcount := errcount +1;
    --mark the document invalid
     valid := FALSE;
   --put 2nd through nth error on a new line
   IF errcount > 1 THEN
     errors := errors ||CHR(10);
   END IF;
   errors := errors || (||errcount||)  ||ruleset_name|| ||curRule.name;
  --move the invalid document to the XMLTYPE failed <netname> rules table for the network , add a document link to the report that when clicked will call the XML for Ops use.
 END IF;
 END LOOP;
END IF;
END;
END validate;

Open in new window

0
Geert BormansInformation ArchitectCommented:
OK, I see, I assume this is Oracle code?
XPath replace can indeed replace stuff by regular expression, but it is not an inplce replacement, it directs to teh "output" whatever that is. Sounds a bit XQuery like. Let me study your code and see if I have an idea

cheers

Geert
0
dcfreyerAuthor Commented:
Geert.

I very much appreciate the attention you are giving this issue - I know you are quite busy with your own work.

Yes, it is Oracle PL/SQL.

Possibly Xpath could send the replace output to a variable then use the variable.  

As an update, I spoke with my requirement's folks, and the customer would accept the "remark" string-text being removed leaving an empty element.  Can we use XPath  remove() function to strip it in place?

Cheers Sir,

David

0
dcfreyerAuthor Commented:
The use of XPath within Regular Expressions is still an issue.  Any further thoughts would be appreciated.

Thanks!!
0
Geert BormansInformation ArchitectCommented:
@dcfreyer,

hey, I have to apologize that this question lost my attention.
I have to admit that I got lost in the oracle script code.
I don't think I can give you any further assistance.
I am really sorry for that
I hope you find a solution one way or another
Good Luck

Geert
0
Geert BormansInformation ArchitectCommented:
you could however have an intermediate step...
build in an XSLT step (could be XSLT1 if that helps)
so after you got the XML from the database, make some corrections using XSLT before passing it on to the next process.
If that approach sounds appealing, I could help you with that.
I don't have the knowledge to assit you in doing all in the database directly
cheers

Geert
0
dcfreyerAuthor Commented:
It appears that Geert has an idea for a solution using XSLT.  I may be asking too much to try and do what I wnat entirely in the database.  Please reopen that Geert may continue to offer his valuable help.

Appreciate it.
0
dcfreyerAuthor Commented:
It appears that Geert has an idea for a solution using XSLT.  I may be asking too much to try and do what I wnat entirely in the database.  Please reopen that Geert may continue to offer his valuable help.

Appreciate it.
0
Geert BormansInformation ArchitectCommented:
Hi, so I am back on it,
can you show me the XML that comes out of the database, and tell me what you want changed, I will then write you an XSLT that fiters what you need
cheers

Geert
0
dcfreyerAuthor Commented:
Geert,

Thank you very much for the come back.

I have attached a file that contains snippets from the XSD and from the generated XML.  It is probably more than you need, however giving too much is better than giving not enough information

Below the dashed lines in the attachment are short explanations with highlighted sections related to the issue.  

Essentially the generated XML document contains many <remark> elements that optionally may contain the <code> attribute -- it is the <code> attribute that must be evaluated for 'P' and if found the contents of <value> must be stripped and replaced with "Not Available On This Network."

<remark>
    <classification sec:classification="U" sec:ownerProducer="USA">UNCLASSIFIED</classification>
<value>This is a test batch comment.</value>
<code>P</code>
</remark>

Lastly, and I fear I am asking too much, if possible can you include the instructions on using PL/SQL to call the XSL when the value "P" is found?

Again, I very much appreciate your professionalism and the assistance you are providing.

Respectfully,
David
EE---RemarksTestDoc.txt
0
Geert BormansInformation ArchitectCommented:
Here is an XSLT that copies the entire XML, but changes the value of <value> whan <code> is P inside a <remark>
This approach is very extensible depending of what you need to check as code values (simply add an extra when clause)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="node()">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="node()"/>
    </xsl:copy>
</xsl:template>
    <xsl:template match="remark/value">
        <xsl:choose>
            <xsl:when test="../code = 'P'">
                <value>
                    <xsl:text>Not Available On This Network.</xsl:text>
                </value>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:copy-of select="@*"/>
                    <xsl:apply-templates select="node()"/>
                </xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
     </xsl:template>
</xsl:stylesheet>

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Geert BormansInformation ArchitectCommented:
No, you are not asking too much :-)
Posting a question on EE should give you a full solution, not a half one....

Having said that, I don't have a clue how to lounge the XSLT from withing PL/SQL.
Maybe this can help
http://www.bd.cesma.usb.ve/oracle9i/appdev.920/a96621/adx21xsp.htm

you don't necessarily have to use the oracle SDK,
I assume there is some sort of process that gets the XML from the database,
you can always glue an XSLT after that.
For that it is important that I know how you get the XML from the database,
batch script, java,...

cheers

Geert
0
dcfreyerAuthor Commented:
The process is XML Instance documents are recevied in either of two ways.  From inside the firewall they are submitted as CLOB data.  Outside the firewall they are submitted as BFILEs.  My plan was to received them both into an ANYDATA Queue then transform them into XMLType for validation and rules processing agains an XML Schema based table.

Once processing is complete, a transformation back to BFILE would be made then they would be exported to the next subsystem.
0
dcfreyerAuthor Commented:
Your XSLT solution is right on the mark Geert.  Thank you.
0
Geert BormansInformation ArchitectCommented:
welcome, I am glad you got helped finally :-)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
XML

From novice to tech pro — start learning today.